Code Coverage Example For Novice Apex Class

The unit test discussed in this post evaluates an Apex Trigger designed for the User object. This trigger populates specific fields whenever a User is created or updated, ensuring the visibility of certain User attributes across Salesforce Communities. For a detailed explanation of the trigger, please refer to the corresponding post.

According to the Apex Code Developer’s Guide, unit tests are class methods that validate the proper functioning of a specific piece of code. These methods don’t require arguments, refrain from committing data to the database, avoid sending emails, and are identified with either the testMethod keyword or the isTest annotation in the method definition. Additionally, test methods must be housed in test classes, which are classes annotated with isTest.

To initiate our unit test, we will create the Salesforce class while adhering to the mentioned guidelines.

@isTest
private class userBeforeTest {
	
	static testMethod void insertUpdateUser() {
		//do something
	}

}

As observed, we have annotated the Apex Class with the @isTest annotation, and the access level for this class is set to private. This is permissible because classes and methods marked with the @isTest annotation can be either private or public. The testing framework can identify and execute the test methods irrespective of their access level. Additionally, the class has been named userBeforeTest, mirroring the name of the Apex Trigger under examination. However, the naming of any unit test class is arbitrary, and this convention is a personal choice for code organization.

The method in this class is declared as static. When a method or variable is declared as static, it is initialized only once when the class is loaded. The method is also flagged with the testMethod keyword, set as void since nothing is returned, and named insertUpdateUser, which is arbitrary and can be chosen based on preference.

It’s worth noting that prior to Salesforce API version 24, unit tests could access existing data in a given org. However, if you’re developing in a recently created Salesforce org, you are likely using a much later version of the API. At the time of this post, the latest API version is 31. An exception to this rule is data from the Profile SObject, which is accessible even in current API versions.

Given that we are testing the functionality of a User trigger, our objective is to create a User. To achieve this, we need to obtain a profile Id since ProfileId is mandatory for User inserts.

static testMethod void insertUpdateUser() {
	//grab a profile
	Profile p = [SELECT Id FROM Profile WHERE Name = 'System Administrator'];
	Test.startTest(); //switch to testing context
	//create a test user
	List<User> users = new List<User>(); //list for holding the new user records for insertion
	users.add(new User(Alias = 'test', Email = 'test@interactiveties.com', EmailEncodingKey = 'ISO-8859-1', FirstName = 'Tess', LanguageLocaleKey = 'en_US', LastName = 'Dachshund', LocaleSidKey='en_US', ProfileId = p.Id, UserName = 'test@interactiveties.com', TimeZoneSidKey = 'America/Denver')); //provide the details of the new User record
	insert users; //insert the list of Users
	Test.stopTest();
}

In this example, it might appear excessive, but we are introducing the startTest method right after obtaining the Profile Id in the provided code. The startTest method introduces an additional context to the current context and essentially resets the governor limits. Incorporating the startTest method is considered good practice in unit tests as it allows you to separate the data creation code from the actual testing code. This ensures that any limits nearing their thresholds during the data creation phase of your unit test logic are reset for the subsequent testing logic. In this instance, we reset the governors immediately after querying the Profile, enabling us to insert a User and utilize the refreshed set of governors for triggers triggered when the User is added to the database.

After inserting the User, our next step is to verify that the trigger indeed fired and produced the expected result. This involves querying the database for the User record and confirming that the record contains the anticipated values for the fields.

static testMethod void insertUpdateUser() {
	//grab a profile
	Profile p = [SELECT Id FROM Profile WHERE Name = 'System Administrator'];
	Test.startTest(); //switch to testing context
	//create a test user
	List<User> users = new List<User>(); //list for holding the new user records for insertion
	users.add(new User(Alias = 'test', Email = 'test@interactiveties.com', EmailEncodingKey = 'ISO-8859-1', FirstName = 'Tess', LanguageLocaleKey = 'en_US', LastName = 'Dachshund', LocaleSidKey='en_US', ProfileId = p.Id, UserName = 'test@interactiveties.com', TimeZoneSidKey = 'America/Denver')); //provide the details of the new User record
	insert users; //insert the list of Users
	//validate that the trigger populated the values we planned
	User u = [SELECT UserPreferencesShowCityToExternalUsers, UserPreferencesShowCountryToExternalUsers, UserPreferencesShowEmailToExternalUsers, UserPreferencesShowStateToExternalUsers, UserPreferencesShowTitleToExternalUsers, UserPreferencesShowWorkPhoneToExternalUsers FROM User WHERE Id =:users[0].Id]; //query for the fields
	//assert that all the user external values in question are now true
	System.AssertEquals(true, u.UserPreferencesShowCityToExternalUsers);
	System.AssertEquals(true, u.UserPreferencesShowCountryToExternalUsers);
	System.AssertEquals(true, u.UserPreferencesShowEmailToExternalUsers);
	System.AssertEquals(true, u.UserPreferencesShowStateToExternalUsers);
	System.AssertEquals(true, u.UserPreferencesShowTitleToExternalUsers);
	System.AssertEquals(true, u.UserPreferencesShowWorkPhoneToExternalUsers);
	Test.stopTest(); //switch out of testing context
}

In some cases this could be sufficient for meeting the 75% code coverage requirement that Salesforce requires on all code within your org. However, we need to make sure that the logic also fires and performs as expected when we update a User too. Again, some developers may look at this as overkill but I believe it is good practice to test as thoroughly as possible in order to reduce the potential for surprises downstream. The full unit test is below.

/*
	Created by: Greg Hacic
	Last Update: 1 October 2014 by Greg Hacic
	Questions?: greg@interactiveties.com
	
	Notes:
		- Tests for userBefore.trigger
*/
@isTest
private class userBeforeTest {
	
	static testMethod void insertUpdateUser() {
		//grab a profile
		Profile p = [SELECT Id FROM Profile WHERE Name = 'System Administrator'];
		Test.startTest(); //switch to testing context
		//create a test user
		List<User> users = new List<User>(); //list for holding the new user records for insertion
		users.add(new User(Alias = 'test', Email = 'test@interactiveties.com', EmailEncodingKey = 'ISO-8859-1', FirstName = 'Tess', LanguageLocaleKey = 'en_US', LastName = 'Dachshund', LocaleSidKey='en_US', ProfileId = p.Id, UserName = 'test@interactiveties.com', TimeZoneSidKey = 'America/Denver')); //provide the details of the new User record
		insert users; //insert the list of Users
		//validate that the trigger populated the values we planned
		User u = [SELECT UserPreferencesShowCityToExternalUsers, UserPreferencesShowCountryToExternalUsers, UserPreferencesShowEmailToExternalUsers, UserPreferencesShowStateToExternalUsers, UserPreferencesShowTitleToExternalUsers, UserPreferencesShowWorkPhoneToExternalUsers FROM User WHERE Id =:users[0].Id]; //query for the fields
		//assert that all the user external values in question are now true
		System.AssertEquals(true, u.UserPreferencesShowCityToExternalUsers);
		System.AssertEquals(true, u.UserPreferencesShowCountryToExternalUsers);
		System.AssertEquals(true, u.UserPreferencesShowEmailToExternalUsers);
		System.AssertEquals(true, u.UserPreferencesShowStateToExternalUsers);
		System.AssertEquals(true, u.UserPreferencesShowTitleToExternalUsers);
		System.AssertEquals(true, u.UserPreferencesShowWorkPhoneToExternalUsers);
		//update the user record
		List<User> userUpdates = new List<User>(); //list for holding the new user records for insertion
		userUpdates.add(new User(Id = users[0].Id, UserPreferencesShowCityToExternalUsers = false, UserPreferencesShowCountryToExternalUsers = false, UserPreferencesShowEmailToExternalUsers = false, UserPreferencesShowStateToExternalUsers = false, UserPreferencesShowTitleToExternalUsers = false, UserPreferencesShowWorkPhoneToExternalUsers = false)); //update all the fields to false
		update userUpdates; //process updates
		Test.stopTest(); //switch out of testing context
		//validate that the values are all still true
		u = [SELECT UserPreferencesShowCityToExternalUsers, UserPreferencesShowCountryToExternalUsers, UserPreferencesShowEmailToExternalUsers, UserPreferencesShowStateToExternalUsers, UserPreferencesShowTitleToExternalUsers, UserPreferencesShowWorkPhoneToExternalUsers FROM User WHERE Id =:users[0].Id]; //query for the fields
		System.AssertEquals(true, u.UserPreferencesShowCityToExternalUsers);
		System.AssertEquals(true, u.UserPreferencesShowCountryToExternalUsers);
		System.AssertEquals(true, u.UserPreferencesShowEmailToExternalUsers);
		System.AssertEquals(true, u.UserPreferencesShowStateToExternalUsers);
		System.AssertEquals(true, u.UserPreferencesShowTitleToExternalUsers);
		System.AssertEquals(true, u.UserPreferencesShowWorkPhoneToExternalUsers);
	}

}

As depicted, I’ve included comments at the beginning of the code to specify the code’s creator, the last modification made, the modification date, and additional notes regarding the Apex Trigger that this unit test specifically addresses. I’ve found that having this information significantly facilitates troubleshooting over time.