Beginner Apex Class Code Coverage Example

In this post I will be providing the Apex unit test code coverage for the trigger which was written in my last post titled Beginner Apex Trigger Example. As in that last post, this code is intended for Salesforce developers that are just starting out or administrators looking to learn more about Apex Classes.

The unit test written in this post is testing an Apex Trigger that was written on the User object, which will populate the values of certain fields every time a User is created or updated. This is done to ensure that certain User attributes are visible across Salesforce Communities. For a full explanation of the trigger please see that post.

As per the Apex Code Developer's Guide, 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, send no emails and are flagged with the testMethod keyword or the isTest annotation in the method definition. Also, test methods must be defined in test classes, that is, classes annotated with isTest.

To begin our unit test we will create the Salesforce class keeping the above information in mind.

@isTest
private class userBeforeTest {
	
	@isTest //defines method for use during testing only
	static void insertUpdateUser() {
		//do something
	}

}

As you can see, we've defined the Apex Class with the @isTest annotation and the access level for this class is private. This is okay because classes and methods defined with the @isTest annotation can be either private or public. The testing framework can always find the test methods and execute them regardless of their access level. You will also notice that we've named the class userBeforeTest, which is similar to the Apex Trigger we are testing. However, the name of any unit test class is arbitrary. This naming convention is just something I do to keep my code organized.

I've declared the method in this class as static. When you declare a method or variable as static, it's initialized only once when a class is loaded. We've also flagged the method using the testMethod keyword, void because there is nothing returned in the method and named it insertUpdateUser, which is arbitrary and may be named anything you like.

Before the release of the Salesforce API version 24, unit tests could access existing data in a given org. If you're developing in a recently created Salesforce org then you are using a much later version of the API. As of the time of this post the latest API version is 31. Data from the Profile SObject is one of the exceptions to this rule. In current versions of the API you are permitted access to Profile records.

Since we are testing the functionality of a User trigger we want to create a User. In order to create a User we need to have a profile Id because ProfileId on User inserts is mandatory.

@isTest //defines method for use during testing only
static 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();
}

It may seem overkill in this example but we are including the startTest method right after we grab the Profile Id in the above code. The startTest method adds an additional context to the current context and basically resets the governor limits. It is good practice to use the startTest method in your unit test because it allows you to isolate the data creation code from the actual testing code and ensure that any limits you may have been closing in on during the data creation portion of your unit test logic are reset for the logic you actually plan on invoking and testing. In this case we are resetting the governors right after the query for the Profile so that we can then insert a User and use that new set of governors for the triggers that fire when the User is inserted into the database.

Now that we've inserted the User we need to validate that the trigger actually fired and we got the result we anticipated. This is done by querying the database for the User record and asserting that the record contains the values for the fields we expected.

@isTest //defines method for use during testing only
static 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 {
	
	@isTest //defines method for use during testing only
	static 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 you can see I added some comments at the top of the code in order to indicate the person that created the code, last modified the code, when they made the modification and some other notes about the Apex Trigger that this unit test actual covers. I find that this information make troubleshooting much easier over time.

Automated Exchange Rates in Salesforce.com

Reduce Repetitive Tasks, Eliminate Errors & Free Up Your Administrators.

Birthday Reminders for Salesforce.com

It might lead to a sale. Or it might make you feel good.