You need to sign in to do that
Don't have an account?
Zeeshan Hussain
Problem with testing future method in Salesforce
Hi guys,
I'll give you a little background information of what I am trying to achieve and maybe some experienced developers here could help to explain the error of my ways.
Aim of the future class
I have a 'Contract' object and a 'Contract Participant' object that is related to the contract.
When a field called 'Contract_To__c' (The contract end date) is changed on the contract, the future class is called by a trigger and then the contract participant end date on the contract participant is updated automatically to the same value to reflect the change if the contract end date was originally the same as the contract participant end date
What I am doing
I have a test class set up with test data. And then within the Test.StartTest() and StopTest() methods, I call the future method, passing in the parameter values after updating the contract end date. After the stopTest() method, I am logging the participant end date to see if the future class has updated this to reflect the contract end date. This does not happen.
Below is the code for my test class and the class for my future method.
Test class:
Future Method/Class
Sorry if this was too much information or if anything was not clearly explained, I am more than happy to explain things further.
Thank you for your time.
I'll give you a little background information of what I am trying to achieve and maybe some experienced developers here could help to explain the error of my ways.
Aim of the future class
I have a 'Contract' object and a 'Contract Participant' object that is related to the contract.
When a field called 'Contract_To__c' (The contract end date) is changed on the contract, the future class is called by a trigger and then the contract participant end date on the contract participant is updated automatically to the same value to reflect the change if the contract end date was originally the same as the contract participant end date
What I am doing
I have a test class set up with test data. And then within the Test.StartTest() and StopTest() methods, I call the future method, passing in the parameter values after updating the contract end date. After the stopTest() method, I am logging the participant end date to see if the future class has updated this to reflect the contract end date. This does not happen.
Below is the code for my test class and the class for my future method.
Test class:
@isTest public class TestClassZee { public static testMethod void test_ContractParticipant(){ Date sys_lastYearStart = Date.newInstance(Date.Today().Year()-1,1,1); Date sys_nextYearEnd = Date.newInstance(Date.Today().Year()+1,12,31); //Dynamically obtain the first value from the global division picklist Schema.DescribeFieldResult fieldResult = Portfolio__c.Team__c.getDescribe(); List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues(); String firstValue = ple[0].getLabel(); //Insert a workstream List<Portfolio__c> wsToInsert = UtilityClass.getWorkstreams(1, 'Agreement', firstValue); insert wsToInsert; //Insert a supplier List<Account> supplierToInsert = UtilityClass.getSuppliers(2); insert supplierToInsert; //Create a contract List<HTE_Contract__c> conToInsert = UtilityClass.getContracts(2, 'valid', supplierToInsert[0].Id, wsToInsert[0].Id); insert conToInsert; //Create an opportunity List<Opportunity> oppToInsert = UtilityClass.getOpportunities(2, supplierToInsert[0].Id, wsToInsert[0].Id, 'Discussion Required'); insert oppToInsert; //Create a contract participant List<Contract_Participant__c> cpToInsert = UtilityClass.getParticipants(1, conToInsert[0].Id, supplierToInsert[0].Id, oppToInsert[0].Id, sys_lastYearStart, sys_nextYearEnd); insert cpToInsert; /*System.debug(LoggingLevel.INFO, 'Checking workstream id ' + wsToInsert[0].Id); System.debug(LoggingLevel.INFO, 'Checking account id ' + supplierToInsert[0].Id); System.debug(LoggingLevel.INFO, 'Checking opp id ' + oppToInsert[0].Id); System.debug(LoggingLevel.INFO, 'Checking contract id ' + conToInsert[0].Id); System.debug(LoggingLevel.INFO, 'Checking contract participant id ' + cpToInsert[0].Id);*/ Test.startTest(); //Change the to date Date oldDate = conToInsert[0].Contract_To__c; conToInsert[0].Contract_To__c = Date.valueof('2020-01-01'); conToInsert[0].Latest_Modification__c = 'Changing contract To date'; update conToInsert; Date newDate = conToInsert[0].Contract_To__c; System.assertEquals(Date.valueof('2020-01-01'), conToInsert[0].Contract_To__c); //Call the future class FutureCPDateUpdate.updateParticipantEndDates(conToInsert[0].Id, oldDate, newDate); Test.stopTest(); System.debug(LoggingLevel.INFO, 'Logging cp end date ' + cpToInsert[0].Participant_To__c); } }
Future Method/Class
public class FutureCPDateUpdate { @future(callout = true) public static void updateParticipantEndDates(Id contractId, Date oldDate, Date newDate) { List<Contract_Participant__c> cp = [SELECT Id, Participant_To__c, Participant_From__c FROM Contract_Participant__c WHERE HTE_Contract__c =:contractId ]; for(Contract_Participant__c cp2 : cp) { if(cp2.Participant_To__c == oldDate) { cp2.Participant_To__c = newDate; } } update cp; } }When I make this change myself without running the code, I have a trigger which calls the future method and it updates the participant end dates just fine. In the future method, it performs a SOQL query for a Contract Participant record. Could it be because It cannot query for test data? I don't see a way around this. I appreciate that I am new to this.
Sorry if this was too much information or if anything was not clearly explained, I am more than happy to explain things further.
Thank you for your time.
I see couple of issues here.
1. You have already calling the future class from trigger. So when you update the Contract in your test class the Trigger and so the future class will be called there itself. So no need to call explicitly in your test class.
2. future classes are run asynchronosly, that is the execution of the future class will be internaly in the queue and server picks it up whenever its free. As you are updating the contract participant object in this future class the current test class instance will not have any access to updated values. In your debug statement "cpToInsert[0].Participant_To__c" this will always return the old value that is set in the test class instance. To get the updated vales you need to requery using select statment. But even that might not work as the future class might not have executed by the time your select statment is executing. Provide some sleep time before your select statment(may be like 10-20 seconds).
Please mark as best answer if it gave some information for you..
All Answers
I see couple of issues here.
1. You have already calling the future class from trigger. So when you update the Contract in your test class the Trigger and so the future class will be called there itself. So no need to call explicitly in your test class.
2. future classes are run asynchronosly, that is the execution of the future class will be internaly in the queue and server picks it up whenever its free. As you are updating the contract participant object in this future class the current test class instance will not have any access to updated values. In your debug statement "cpToInsert[0].Participant_To__c" this will always return the old value that is set in the test class instance. To get the updated vales you need to requery using select statment. But even that might not work as the future class might not have executed by the time your select statment is executing. Provide some sleep time before your select statment(may be like 10-20 seconds).
Please mark as best answer if it gave some information for you..