You need to sign in to do that
Don't have an account?
Jack Volkov
Best Practice for testing record updates within a for loop
In this apex class the logic is to update a custom lead field with a math.random() value.
This unit test verifies that inserting the task causes the logic in the apex class above to run and update the leads as expected.
What is the best practice for test coverage for the lines that are missing?
public class leadRandomNumber { /* update lead status for leads related to the tasks */ public static void updateRandomNumber (List<Lead> leadsFromTasks) { system.debug ('***** entering method leadRandomNumber.updateRandomNumber class *****'); List<Lead> leadsToUpdate = new List<Lead>(); List<Lead> leads = new List<Lead>([select Id, RandomNumber__c from Lead where Id IN :leadsFromTasks and Status='Attempting' and createddate = this_year and RandomNumber__c = null]); system.debug('updateRandomNumber leads queried:' + leads.size()); // for leads related to the tasks apply a random number to the leads if they do not yet have one for(lead ld: leads) { if(ld.RandomNumber__c == null) { Double rand = math.random(); ld.RandomNumber__c = rand; } leadsToUpdate.add(ld); } update leadsToUpdate; system.debug('updateRandomNumber leadsToUpdate: ' + leads.size()); } }
This unit test verifies that inserting the task causes the logic in the apex class above to run and update the leads as expected.
/* - For leads whose lead status was just updated as the result of an attempting call - check that the random number was set */ @isTest private class leadRandomNumberTest { static testMethod void insertAttemptingCall() { system.debug('Inserting outbound preview call tasks as a new logo rep...'); User newLogoRep = [select id from user where isactive = true and profile.name = 'Inside Sales User' limit 1]; QueueSobject smbQueue = [select queue.id from queuesobject where queue.name = 'SMB AE Queue']; Lead l = new Lead(Company='Company',LastName='Test',Phone='8885551234',Status='Open',LeadSource='Marketing', ownerid=smbQueue.queue.id); insert l; // bulk insert a list of calls related to the lead Task task = new Task(WhoId=l.Id, OwnerId=newLogoRep.Id, Type = 'Call', Five9__Five9CallType__c='Outbound Preview', Subject='Call Attempting', Status='Completed', Five9__Five9SessionId__c='fb3636336363', ActivityDate=date.today(), Five9__Five9HandleTime__c = '00:01:59', Five9__Five9WrapTime__c = '00:00:29'); test.startTest(); system.RunAs(newLogoRep) { insert task; } system.debug('Asserting that the leads status was updated to Attempting and it now has a RandomNumber value...'); Task insertedTask = [select Id, Status from Task where Id =: task.id]; System.assertEquals('Completed',insertedTask.Status); // check that the lead was updated as expected Lead insertedLead = [select Id, Status, RandomNumber__c from Lead where Id =: l.Id]; System.assertEquals('Attempting',insertedLead.Status); System.assertNotEquals(null,insertedLead.RandomNumber__c); system.debug('random number set to: ' + insertedLead.RandomNumber__c); test.stopTest(); } }However the test coverage for the apex class is only 56% as the updates inside the for loop are not covered.
What is the best practice for test coverage for the lines that are missing?
If so, I think you have an error in your test - the Status on the test Lead = 'Open', but your query looks for Status='Attempting'? So I don't think the loop would be invoked since no records match the query...
The assertions in leadRandomNumberTest.insertAttemptingCall line 26-27 is passing so leadRandomNumber.updateRandomNumber is indeed invoked.
What is the best way to get test coverage for leadRandomNumber.updateRandomNumber line 14-17?
@isTest
private class testLeadRandomNumber {
static testMethod void insertAttemptingCall() {
List<Case> nonNullRandomNumber = new List<Case>();
Case nullRand = new Case();
List<Case> nullRandList = new List<Case>();
//make some new obj's with null random__c
for(Integer x = 0; x < 20; x++){
nullRandList.add(new Case(status='Unassigned'));
}
insert nullRandList;
leadRandomNumber.updateRandomNumber([select id, ruben__RandomNumber__c from Case
where ruben__RandomNumber__c = null]);
//Now you could assert that the following list [select id from case where ruben__RandomNumber__c = null] has a size of zero
//or that it's null... which would imply that your updateRandomNumber() worked.
}
}
Coverage is now 86% but only because the code is condensed so their is less to cover.
But the logic inside of the IF statement at line 12 is still not covered. How can this not be getting invoked if the RandomNumber__c value, which default is NULL, is being set to a math.random() value? This is the only method that would set the RandomNumber__c value.
Does the fact that leadsFromTasks.size() = 1 prove the method was invoked?
Screenshot of debug log: http://screencast.com/t/tYm1ytd8PIB
1. A task is inserted
2. A task trigger runs which calls a class method which updates the lead status depening on the task the result
3. At the end of the method that updates the lead status, a separate class method is called, which is leadRandomNumber.updateRandomNumber
4. The method in leadRandomNumber.updateRandomNumber updates the random number value if lead status = attempting (which would have been udpdated in step 2)
Please try a simplified test that doesn't rely on using triggers; since you updated updateRandomNumber to not execute SOQL, just have a test method create a Lead in memory that you know meets the criteria, pass that lead in, and then verify it changed as expected.
Debug log: http://content.screencast.com/users/jvolkov/folders/Jing/media/801f84f5-7946-44dd-822a-af6ad5878552/00002892.png