Best Practices for Unit testing
- johnsontitus
- May 21, 2020
- 2 min read
Updated: Jun 1, 2020
Unit tests are class methods that verify whether a particular piece of code is working properly. Unit test methods take no arguments, commit no data to the database
Use positive test case with valid input or within governor limits
Use negative test case with invalid input or outside governor limits
Testing code with different users
Controller extensions and custom controllers, like all Apex scripts, should be covered by unit tests.
Refer to the following example - https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_controller_error_handling.htm
Unit test the flows - eg, a flow that takes order object with name and desc as input, and generates its record id as output.
In the Unit test,
Create a map to store the input
instantiate the flow with the input parameter
call the flow with start() method on the flow instance
call the getVariableValue() method on the flow instance to retrieve the output variables.
refer to the following example - https://andyinthecloud.com/2014/10/26/calling-flow-from-apex/
Unit test the process - https://www.desynit.com/good-systems-blog/salesforce/writing-apex-tests-for-salesforce-flows-and-process-builders/
Unit test should have 3 parts:
Setting up test data
Calling the execute method
Verify the result using System.assert().
Eg: Consider a trigger on Contact to trigger when its owner changes, also a workflow rule - 'when contact's email address changes' it should store the old email address in a contact field.
Note - check how the static variable is used in the unit test.
public class ProgramFlowExperiment {
public static Integer EmailCounter = 0;
private void SendEmail()
{
EmailCounter++;
System.Debug('Queueing email to send');
}
private void SendQueuedEmails()
{
System.Debug('Sending Email queue');
}
private static Set<ID> AlreadyProcessedList = null;
public void HandleContactUpdateTrigger(List<Contact> newlist, Map<ID, Contact> oldmap)
{
if(AlreadyProcessedList==null) AlreadyProcessedList = new Set<ID>();
for(Contact ct: newlist)
{
if(AlreadyProcessedList.contains(ct.id)) continue;
if(ct.OwnerID != oldmap.get(ct.ID).OwnerID)
{
AlreadyProcessedList.add(ct.id);
SendEmail();
}
}
SendQueuedEmails();
}
}
trigger ContactOwnerChangeTrigger on Contact (after update) {
ProgramFlowExperiment pf = new ProgramFlowExperiment();
pf.HandleContactUpdateTrigger(trigger.new, trigger.oldMap);
}
Unit Test:
@isTest
public class TestContactOwnerChange {
static testMethod void TestOwnerChange() {
// Create some test contacts
List<Contact> newcontacts = initTestContacts('c', 5);
user u = initTestUser('myname', 'myname');
System.runAs(u)
{
// These contacts will be created with a fake user as owner
insert newcontacts;
}
Test.StartTest();
for(Contact ct: newcontacts)
{
ct.OwnerID = UserInfo.getUserId();
ct.Email = 'someone@somewhere.com';
}
update newcontacts;
Test.StopTest();
System.AssertEquals(newcontacts.size(), ProgramFlowExperiment.EmailCounter);
}
public static List<Contact> initTestContacts(String prefix, Integer count)
{
List<Contact> results = new List<Contact>();
for(Integer x=0; x<count; x++)
{
results.add(new Contact(LastName = prefix + '_' + string.ValueOf(x),
email = prefix + '_'+string.ValueOf(x)+'@apexfundementals.com'));
}
return results;
}
public static User initTestUser(String username, String thealias)
{
User u = new User(Alias = thealias,
Email = username + '@apexfundementals.com',
FirstName='Joe', LastName= username,
TimeZoneSidKey = 'America/Los_Angeles',
UserName = username + '@apexfundementals.com',
UserPermissionsMarketingUser=true, LocaleSidKey='en_US',
EmailEncodingKey='UTF-8', LanguageLocaleKey = 'en_US');
u.ProfileID = userinfo.getProfileId();
return u;
}
}

Comments