Proper Unit Test Structure in Apex

A unit test is typically described as:

a method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine if they are fit for use.

In Salesforce, unit tests are really much more similar to integration tests.

Integration testing is the phase in software testing in which individual software modules are combined and tested as a group.

The reason I say this is due to the fact that Salesforce currently lacks a good mock framework. With a very positive change in Spring ’12 that forces the isolation of test data, the developer now has to generate the entire data model whenever they want to write a unit test. This is extremely important to know as this will drive how we structure our unit tests. Let’s take a look at a scenario.

Suppose you have some method that determines the difference in the amount of Widget__c‘s a Foo__c has to the Count_One__c or Count_Two__c of a Stub__c based on the Use_Count_One__c flag. I want to keep this simple enough to get the concepts across but complex enough to show some of the better real world scenarios so bear with me here.

public class ExampleController{
	
	public Integer differenceInFooWidgetsAndStubCount(Id fooId, Id stubId){
		Foo__c foo = [
			SELECT
				Id,
				(SELECT Id FROM Widget__r)
			FROM
				Foo__c
			WHERE
				Id = :fooId
		];
		
		Stub__c stub = [
			SELECT
				Id, Count_One__c, Count_Two__c, Use_Count_One__c
			FROM
				Stub__c
			WHERE
				Id = :stubId
		];
		
		if(stub.Use_Count_One__c){
			return foo.Widget__r.size() - stub.Count_One__c;
		}else{
			return foo.Widget__r.size() - stub.Count_Two__c;
		}
	}
}

Basic Structure of The Test

Now, something important to note is that with starting with Summer ’13 all unit tests should be in their own class. Finally! This is great news as it is starting to force developers to write cleaner code (simply by delineating between production code and unit tests). So, knowing this, we need to make a test class. I typically like to use the name of the original class appended with Test. Let’s take a look at a class with some pseudo code for a test method.

@isTest
public class ExampleControllerTest{
	static testMethod void testDifferenceInFooWidgetsAndStubCountOne(){
		// Generate test model
	
		// Perform test logic
		
		// Assert logic
	}
}

First thing to notice is we used the @isTest annotation. By marking our test with that annotation, it forces all code in that class to be run in the testing context only. It also doesn’t count against your code coverage limits or against your Apex code limits. Now, looking down at our test method you see instead of annotating it @isTest I went ahead and used testMethod instead. The two designations are interchangable and I could have easily have written the method as:

@isTest
static void testDifferenceInFooWidgetsAndStubCountOne(){
	// Logic
}

The benefit of using @isTest is that you can provide the SeeAllData="true" flag to it to access your organization’s data (although only do this if you absolutely have to). I typically prefer testMethod so for this example we will stick with that.

Setting up the Data Model

Let’s go ahead and start setting up more of our code. Let’s generate our test model so we have some data to work with.

@isTest
public class ExampleControllerTest{
	static testMethod void testDifferenceInFooWidgetsAndStubCountOne(){
		Foo__c foo = new Foo__c();
		insert foo;
		List<Widget__c> widgets = new List<Widget__c>();
		for(Integer i = 0; i<3; i++){
			widgets.add(new Widget(
				Foo__c = foo.Id,
				Foo__r = foo
			));
		}
		insert widgets;
		Stub__c stub = new Stub__c(
			Count_One__c = 1,
			Count_Two__c = 2,
			Use_Count_One__c = true
		);
		insert stub;
	
		// Perform test logic
		
		// Assert logic
	}
}

This is going to set up the test data we need by inserting a Foo__c, 3 Widget__c‘s, and a Stub__c. While this will work, it really isn’t the most efficient way to handle this. First of all, this logic will need to be copy and pasted across every test method. That is a huge issue if for some reason down the line you add a required field to Foo__c for instance and now you have to add that field to every instance of Foo__c you are creating across your entire class. The obvious solution is to encapsulate this logic into methods.

@isTest
public class ExampleControllerTest{
	static testMethod void testDifferenceInFooWidgetsAndStubCountOne(){
		Foo__c foo = generateFoo();
		List<Widget__c> widgets = generateWidgets(foo, 3);
		Stub__c stub = generateStub(true);
	
		// Perform test logic
		
		// Assert logic
	}
	
	private Foo__c generateFoo(){
		Foo__c foo = new Foo__c();
		insert foo;
		return foo;
	}
	
	private List<Widget__c> generateWidgets(Foo__c foo, Integer count){
		List<Widget__c> widgets = new List<Widget__c>();
		for(Integer i = 0; i<count; i++){
			widgets.add(new Widget(
				Foo__c = foo.Id,
				Foo__r = foo
			));
		}
		insert widgets;
		return widgets;
	}
	
	private Stub__c generateStub(Boolean useCountOne){
		Stub__c stub = new Stub__c(
			Count_One__c = 1,
			Count_Two__c = 2,
			Use_Count_One__c = useCountOne
		);
		insert stub;
		return stub;
	}
}

Awesome! We have our generation code separated out for this class. Any time we need to generate a Foo__c for this class, it is in one spot. We even made some of our other fields dynamic (such as adding a count or the useCountOne parameters). We know certain tests are going to want to different values for some of those fields. By parameterizing them, we can make them different per test scenario.

With that said, we still have an issue. Foo__c is going to be used all throughout our org. Even if it isn’t now, it has the potential to be used elsewhere. Do we really want separate methods in all of our test classes for generating a Foo__c? It is the same scenario that we ran into above. To solve that issue, we will move our data setup out into a TestUtilities class and access all of the data generation through static methods.

@isTest
public class ExampleControllerTest{
	static testMethod void testDifferenceInFooWidgetsAndStubCountOne(){
		Foo__c foo = TestUtilities.generateFoo();
		List<Widget__c> widgets = TestUtilities.generateWidgets(foo, 3);
		Stub__c stub = TestUtilities.generateStub(true);
	
		// Perform test logic
		
		// Assert logic
	}
}

@isTest
public class TestUtilities{
	public static Foo__c generateFoo(){
		Foo__c foo = new Foo__c();
		insert foo;
		return foo;
	}
	
	public static List<Widget__c> generateWidgets(Foo__c foo, Integer count){
		List<Widget__c> widgets = new List<Widget__c>();
		for(Integer i = 0; i<count; i++){
			widgets.add(new Widget(
				Foo__c = foo.Id,
				Foo__r = foo
			));
		}
		insert widgets;
		return widgets;
	}
	
	public static Stub__c generateStub(Boolean useCountOne){
		Stub__c stub = new Stub__c(
			Count_One__c = 1,
			Count_Two__c = 2,
			Use_Count_One__c = useCountOne
		);
		insert stub;
		return stub;
	}
}

We really cleaned up our test now. By refactoring we were able to make our test class much cleaner and provide a framework to generate our test data easily. In this scenario it isn’t truly necessary, but I would like to take this one step even further. By utilizing the generic sObject, we can actually limit our DML statements as well.

@isTest
public class ExampleControllerTest{
	static testMethod void testDifferenceInFooWidgetsAndStubCountOne(){
		Map<String, List<sObject>> objectMapping = TestUtilities.generateTestModel(true);
		Foo__c foo = objectMapping.get('Foo__c').get(0);
		Stub__c stub = objectMapping.get('Stub__c').get(0);
	
		// Perform test logic
		
		// Assert logic
	}
}

@isTest
public class TestUtilities{
	public static Foo__c generateFoos(Integer count){
		List<Foo__c> foos = new List<Foo__c>();
		for(Integer i = 0; i<count; i++){
			foos.add(new Foo());
		}
		return foos;
	}
	
	public static List<Widget__c> generateWidgets(List<Foo__c> foos, Integer count){
		List<Widget__c> widgets = new List<Widget__c>();
		for(Foo__c foo:foos){
			for(Integer i = 0; i<count; i++){
				widgets.add(new Widget(
					Foo__c = foo.Id,
					Foo__r = foo
				));
			}
		}

		return widgets;
	}
	
	public static List<Stub__c> generateStubs(Boolean useCountOne, Integer count){
		List<Stub__c> stubs = new List<Stub__c>();
		for(Integer i = 0; i<count; i++){
			stubs.add(new Stub__c(
				Count_One__c = 1,
				Count_Two__c = 2,
				Use_Count_One__c = useCountOne
			));
		}
		return stubs;
	}
	
	public static Map<String, List<sObject>> generateTestModel(Boolean useCountOne){
		List<sObject> objectsToAdd = new List<sObject>();
		List<Foo__c> foos = generateFoos(1);
		List<Stub__c> stubs = generateStubs(useCountOne, 1);
		objectsToAdd.add(foos);
		objectsToAdd.add(stubs);
		insert objectsToAdd;
		objectsToAdd.clear();
		
		List<Widget__c> widgets = generateWidgets(foos.get(0), 3);
		objectsToAdd.add(widgets);
		insert objectsToAdd;
		objectsToAdd.clear();
		
		Map<String, List<sObject>> objectMapping = new Map<String, List<sObject>>();
		objectMapping.put('Foo__c', foos);
		objectMapping.put('Stub__c', stubs);
		objectMapping.put('Widget__c', widgets);
		return objectMapping;
	}
}

Now, I want you to take a moment to really understand what we just did here. The leap we just made isn’t the easiest to understand right away. What we did was utilized Lists of generic sObjects to limit our DML operations. In this scenario, we dropped our total DML operations from 3 down to 2. As mentioned before, this may be a bit overkill for this particular situation, but this is exponentially beneficial after more and more pieces get added to the data model. This is being put in place for the future. We refactored everything to generate Lists of objects as well which will be useful when we test triggers/other functionality. Using this new method, we were able to remove the concept of the Widget__c from our test completely. We don’t need to pass any of the Widget__c‘s info the controller, so we don’t need to bring it into the test at all.

Writing Test Logic

Now that our test data is set up, we can go ahead and start writing some test logic. In this scenario, we will want to create two tests. We need a test to cover the first path of the if statement as well as the else condition.

@isTest
public class ExampleControllerTest{
	static testMethod void testDifferenceInFooWidgetsAndStubCountOne(){
		Map<String, List<sObject>> objectMapping = TestUtilities.generateTestModel(true);
		Foo__c foo = objectMapping.get('Foo__c').get(0);
		Stub__c stub = objectMapping.get('Stub__c').get(0);
	
		Test.startTest();
		ExampleController controller = new ExampleController();
		Integer difference = controller.differenceInFooWidgetsAndStubCount(foo.Id, stub.Id);
		Test.stopTest();
		
		// Assert logic
	}
	
	static testMethod void testDifferenceInFooWidgetsAndStubCountTwo(){
		Map<String, List<sObject>> objectMapping = TestUtilities.generateTestModel(false);
		Foo__c foo = objectMapping.get('Foo__c').get(0);
		Stub__c stub = objectMapping.get('Stub__c').get(0);
	
		Test.startTest();
		ExampleController controller = new ExampleController();
		Integer difference = controller.differenceInFooWidgetsAndStubCount(foo.Id, stub.Id);
		Test.stopTest();
		
		// Assert logic
	}
}

There are a few important things to note here. First, note that we have Test.startTest() and Test.stopTest(). These methods are in place specifically to validate your governor limits. Any code that is run between these two calls with run with their own set of governor limits. This ensures that large data model setups do not effect the governor limits set in place that your code would typically run into by just being run. It is important to notice that both of these methods have separate parameters based into the data model generation, forcing the flow to enter either the positive if condition or falling through to the else condition. Next, notice how we are setting our result back onto a variable in our test. We will be using that in our final step, assertions.

Assertion

The final, and most crucial, part of any test is the assertion. This is the part of your test that will tell you if the method you ran is actually doing what you expect it to do. The sad truth about Apex is that this piece is completely optional to deploy to production. The code we have written already has 100% code coverage. The issue is the only thing the unit tests we wrote validates is that there were no exceptions thrown when the code was run. That simply isn’t very useful. While this is acceptable in Salesforce’s eyes to go to production, it is completely unacceptable in the eyes of any professional programmer. You will be responsible for validating your code is working properly. It is up to you to verify that the controller logic you wrote 6 months ago is still working properly after your latest change to a service it calls. To do this, you absolutely must write assertions. Am I making my point? Always, always write assertions!!

Now that we have that out of the way, Salesforce offers a few different assertion methods on the System class. In this scenario, we will just use the System.assertEquals. Let’s take a look at it in action in our example.

@isTest
public class ExampleControllerTest{
	static testMethod void testDifferenceInFooWidgetsAndStubCountOne(){
		Map<String, List<sObject>> objectMapping = TestUtilities.generateTestModel(true);
		Foo__c foo = objectMapping.get('Foo__c').get(0);
		Stub__c stub = objectMapping.get('Stub__c').get(0);
	
		Test.startTest();
		ExampleController controller = new ExampleController();
		Integer difference = controller.differenceInFooWidgetsAndStubCount(foo.Id, stub.Id);
		Test.stopTest();
		
		System.assertEquals(2, difference, 'The difference should be 2 when Count_One__c is used');
	}
	
	static testMethod void testDifferenceInFooWidgetsAndStubCountTwo(){
		Map<String, List<sObject>> objectMapping = TestUtilities.generateTestModel(false);
		Foo__c foo = objectMapping.get('Foo__c').get(0);
		Stub__c stub = objectMapping.get('Stub__c').get(0);
	
		Test.startTest();
		ExampleController controller = new ExampleController();
		Integer difference = controller.differenceInFooWidgetsAndStubCount(foo.Id, stub.Id);
		Test.stopTest();
		
		System.assertEquals(1, difference, 'The difference should be 1 when Count_Two__c is used');
	}
}

The way System.assertEquals works is it takes two required parameters, expected and actual (in that order) as well as an optional error message. In the above scenario, when Use_Count_One__c is true, the expected difference is 2. If difference comes back as anything but 2, a fatal error will be thrown and the unit test will fail. This is what really wraps the entire test up. It validates that what we expect the method to return actually gets returned. It validates that our code is operating exactly the way we planned.

Another important thing to note is that this logic has been broken up into two separate tests. We could have easily written this logic as a single method, like:

@isTest
public class ExampleControllerTest{
	static testMethod void testDifferenceInFooWidgetsAndStub(){
		Map<String, List<sObject>> objectMapping = TestUtilities.generateTestModel(true);
		Foo__c foo = objectMapping.get('Foo__c').get(0);
		Stub__c stub = objectMapping.get('Stub__c').get(0);
	
		Test.startTest();
		ExampleController controller = new ExampleController();
		Integer difference = controller.differenceInFooWidgetsAndStubCount(foo.Id, stub.Id);
		Test.stopTest();
		
		System.assertEquals(2, difference, 'The difference should be 2 when Count_One__c is used');

		Map<String, List<sObject>> objectMappingTwo = TestUtilities.generateTestModel(false);
		Foo__c fooTwo = objectMappingTwo.get('Foo__c').get(0);
		Stub__c stubTwo = objectMappingTwo.get('Stub__c').get(0);
	
		Test.startTest();
		ExampleController controllerTwo = new ExampleController();
		Integer differenceTwo = controllerTwo.differenceInFooWidgetsAndStubCount(fooTwo.Id, stubTwo.Id);
		Test.stopTest();
		
		System.assertEquals(1, differenceTwo, 'The difference should be 1 when Count_Two__c is used');
	}
}

This would not be a good idea. It invalidates the idea of a “unit” test. We want to make our unit tests as small as possible. Test the smallest piece of functionality you can and have as many tests as possible. This not only keeps the code cleaner but it makes it very easy to identify any issues when a very specific unit test fails.

Wrap Up

I hope some of this has been helpful. From my point of view, the most complex part of the process is the data setup. In non-ideal scenarios where you have to insert 20+ object types to run one of your test methods, the things I have detailed out here on generating your data model can be extremely beneficial. It can help performance in respect to the speed of running your unit tests and the ability of making changes to your data model. The simplest part of any unit test is the actual logic being run. It should be as simple as possible to ensure you have a very specific piece of functionality being tested. This will give you a better insight on what is actually happening when a unit test fails. Finally, the most important part is the assertion. Let me repeat, the most important part is the assertion! I honestly can not stress this enough. The assertion is the actual check that validates your code is working the way you expected. Without that, all you validate is that no exceptions were thrown.

Good luck out there with your testing! Our final code base looks like:

The Actual Code – ExampleController

public class ExampleController
	
	public Integer differenceInFooWidgetsAndStubCount(Id fooId, Id stubId){
		Foo__c foo = [
			SELECT
				Id,
				(SELECT Id FROM Widget__r)
			FROM
				Foo__c
			WHERE
				Id = :fooId
		];
		
		Stub__c stub = [
			SELECT
				Id, Count_One__c, Count_Two__c, Use_Count_One__c
			FROM
				Stub__c
			WHERE
				Id = :stubId
		];
		
		if(stub.Use_Count_One__c){
			return foo.Widget__r.size() - stub.Count_One__c;
		}else{
			return foo.Widget__r.size() - stub.Count_Two__c;
		}
	}
}

Test Class – ExampleControllerTest

@isTest
public class ExampleControllerTest{
	static testMethod void testDifferenceInFooWidgetsAndStubCountOne(){
		Map<String, List<sObject>> objectMapping = TestUtilities.generateTestModel(true);
		Foo__c foo = objectMapping.get('Foo__c').get(0);
		Stub__c stub = objectMapping.get('Stub__c').get(0);
	
		Test.startTest();
		ExampleController controller = new ExampleController();
		Integer difference = controller.differenceInFooWidgetsAndStubCount(foo.Id, stub.Id);
		Test.stopTest();
		
		System.assertEquals(2, difference, 'The difference should be 2 when Count_One__c is used');
	}
	
	static testMethod void testDifferenceInFooWidgetsAndStubCountTwo(){
		Map<String, List<sObject>> objectMapping = TestUtilities.generateTestModel(false);
		Foo__c foo = objectMapping.get('Foo__c').get(0);
		Stub__c stub = objectMapping.get('Stub__c').get(0);
	
		Test.startTest();
		ExampleController controller = new ExampleController();
		Integer difference = controller.differenceInFooWidgetsAndStubCount(foo.Id, stub.Id);
		Test.stopTest();
		
		System.assertEquals(1, difference, 'The difference should be 1 when Count_Two__c is used');
	}
}

Test Utility – TestUtilities

@isTest
public class TestUtilities{
	public static Foo__c generateFoos(Integer count){
		List<Foo__c> foos = new List<Foo__c>();
		for(Integer i = 0; i<count; i++){
			foos.add(new Foo());
		}
		return foos;
	}
	
	public static List<Widget__c> generateWidgets(List<Foo__c> foos, Integer count){
		List<Widget__c> widgets = new List<Widget__c>();
		for(Foo__c foo:foos){
			for(Integer i = 0; i<count; i++){
				widgets.add(new Widget(
					Foo__c = foo.Id,
					Foo__r = foo
				));
			}
		}

		return widgets;
	}
	
	public static List<Stub__c> generateStubs(Boolean useCountOne, Integer count){
		List<Stub__c> stubs = new List<Stub__c>();
		for(Integer i = 0; i<count; i++){
			stubs.add(new Stub__c(
				Count_One__c = 1,
				Count_Two__c = 2,
				Use_Count_One__c = useCountOne
			));
		}
		return stubs;
	}
	
	public static Map<String, List<sObject>> generateTestModel(Boolean useCountOne){
		List<sObject> objectsToAdd = new List<sObject>();
		List<Foo__c> foos = generateFoos(1);
		List<Stub__c> stubs = generateStubs(useCountOne, 1);
		objectsToAdd.add(foos);
		objectsToAdd.add(stubs);
		insert objectsToAdd;
		objectsToAdd.clear();
		
		List<Widget__c> widgets = generateWidgets(foos.get(0), 3);
		objectsToAdd.add(widgets);
		insert objectsToAdd;
		objectsToAdd.clear();
		
		Map<String, List<sObject>> objectMapping = new Map<String, List<sObject>>();
		objectMapping.put('Foo__c', foos);
		objectMapping.put('Stub__c', stubs);
		objectMapping.put('Widget__c', widgets);
		return objectMapping;
	}
}

17 Responses to “Proper Unit Test Structure in Apex”

  1. Patrick Dixon
    September 8, 2013 at 7:53 am #

    in generateTestModel line 43 should be

    insert objectsToAdd;

    rather than

    insert stubs;

    I think

    • September 8, 2013 at 8:10 am #

      Thanks Patrick. You are definitely correct. I updated the post based on your feedback. Sometimes pseudo code can have issues like that lol!

  2. Vincent
    October 1, 2013 at 4:25 pm #

    Great article Jesse ! Somebody from Developer Force and I’m really glad they did !

  3. Rohit
    January 24, 2014 at 7:09 am #

    Hi

    An excellent illustration of a test class. Thanks a lot. I will understand it over time. I just want to confirm few things from you.
    1. Now people are writing constructor in test class and putting all material for the class in it.
    2. is there any updates of illustration you provided after Winter’14 Release.

    Thanks a lot again for your efforts. Looking forward to have such things in future too. Keep it up.

  4. Paul Craft
    May 1, 2014 at 9:33 am #

    I’m getting an error of: “Incompatible element type LIST for collection of SObject” in the TestModel code. What am I missing?

    public static Map<String, List> generateTestModel(){
    List objectsToAdd = new List();
    List accounts = generateAccounts(1);
    objectsToAdd.add(accounts);
    insert objectsToAdd;
    objectsToAdd.clear();

    List contacts = generateContacts(accounts.get(0),3);
    List opportunities = generateOpportunities(accounts.get(0), 3);
    objectsToAdd.add(contacts);
    objectsToAdd.add(opportunities);
    insert objectsToAdd;
    objectsToAdd.clear();

    Map<String, List> objectMapping = new Map<String, List>();
    objectMapping.put(‘Account’, accounts);
    objectMapping.put(‘Contact’, contacts);
    objectMapping.put(‘Opportunity’, opportunities);
    return objectMapping;
    }

    • AClizzle
      May 2, 2014 at 4:13 pm #

      Hi Paul –

      I am having the same issue.

      The problem is the example code is trying to add lists of SObjects to an SObject List.

      I think the correct syntax for defining the objectsToAdd list in this scenario would be:

      List<List objectsToAdd = new List<List>();

      which would allow you to add your list of foos and list of widgets to the objectsToAdd list…

      This then causes another error when you try the insert:

      DML requires SObject or SObject list type: LIST<LIST>;

      Which I think is saying that Apex will let you insert an sObject or a list of sObjects, but not a list of sObject lists.

      The fixes I’ve come up with so far don’t seem very efficient, but I’ll share them anyway:

      1. For each sObject list you want to add to the objectsToAdd list run for loop to iterate over the list and add the sObjects individually:

      for(Foo__c aFoo:foos)(
      objectsToAdd.add(aFoo);
      )

      2. Create the list of Lists as shown above and then iterate over that list and insert each member list individually (this seems like the opposite of what the TestUtilities class is about since it creates a lot of insert calls rather than reducing them)

      • May 3, 2014 at 11:25 am #

        I’ll take a look into this. Potentially something changed but this used to work just fine.

  5. AClizzle
    May 2, 2014 at 4:15 pm #

    Sorry, the Syntax got messed up in my reply:

    The correct syntax to allow for adding the foo list to the objectsToAdd list would be;

    List<List> objectsToAdd = new List<List>();

  6. Isaac
    August 27, 2014 at 2:23 pm #

    The answer came from @Bob_Buzzard in the Developer forums. Short answer, you have to cast the object to an sObject, just like good ol’ Java.

    The following should process fine:

    public static Map<String, List> generateTestModel(Boolean useCountOne){

    List objectsToAdd = new List();
    List foos = generateFoos(1);
    objectsToAdd.add((LIST)foos);
    insert objectsToAdd;

    return objectMapping;

    }

    For more details on the solution, see:
    https://developer.salesforce.com/forums/ForumsMain?id=906F0000000Ad3jIAC

  7. Isaac
    August 27, 2014 at 2:29 pm #

    Back in the test method, you will also need to recast the sObject:

    static testMethod void testDifferenceInFooWidgetsAndStubCountOne(){

    Map<String, List> objectMapping = TestUtilities.generateTestModel(true);
    Foo__c foo = (FOO__C) objectMapping.get(‘Foo__c’).get(0);

    }

    For more details about casting in Apex:
    https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_casting.htm

    • AClizzle
      December 11, 2014 at 1:23 pm #

      @Isaac

      Thanks for that update! I modified my list add method from .add() to .addAll() and cast everything to sObject and back as described in Bob’s post and it seems to be working great.

      I have question on how to expand this easy to understand example to a more complex use case.

      Does anyone have a suggestion on how to populate data for more complex objects? Some of my customs have several required fields and those fields often impact how the code under test should behave.

      My first though was I could just create the test data objects with a hardcoded value in the test utilities class and then modify the fields in the controller test class with the values needed for the test. The problem I see with this is that is requires an update call for each object that gets modified in each test….which again seems like the opposite of the point of the test utilities concept.

      I am now thinking it may make sense to have all of my “generateSObject” methods accept a map of required field names and the desired value as an argument, something like:

      public static CustomObject__c generateCustomObject(Integer count, Map){

      //code to assign map values to CustomObject field values
      }

      Does this seem like a reasonable approach? Is there a better way to do this?

      Thanks,

      Adam

Trackbacks/Pingbacks

  1. Salesforce Certification Series: Advanced Developer | Jesse Altman - September 26, 2013

    […] Write proper unit tests! If you finish your application and you haven’t written any assert statements, you will fail! These need to be well written, well formed unit tests. Trust me, the unit tests are crucial to your success both in this exam and actual development. […]

  2. Chatter Image Gallery using ConnectApi | Jesse Altman - March 17, 2014

    […] class. Now, this doesn’t necessarily follow what I would consider the best way to write a unit test in Apex since I didn’t create a Test utility class, but for the sake of simplicity I just kept […]

  3. Real Unit Tests using ApexMocks | Jesse Altman - June 16, 2014

    […] a year ago, I wrote an article on Proper Unit Test Structure in Apex. In that article I […]

  4. Clean Code on the Force.com Platform | Jesse Altman - August 18, 2014

    […] to generate the data model. I won't go into too many details here, but I highly suggest reading my Proper Unit Test Structure in Apex article which dives into more […]

  5. New Spring ’15 Feature: @testSetup | Jesse Altman - January 26, 2015

    […] good unit test practices (such as using a TestUtils class), this will just be a new aspect of proper unit test structure. Enjoy and feel free to test it out on your own Spring ’15 Pre-Release […]

  6. Beyond Trailhead – Apex Testing | Jesse Altman - June 23, 2015

    […] It was a fantastic idea to call out the usage of a Test Utilities class for creating your data. That is a common mistake I see most new developers make (by not having one). I also thought the mention of branch coverage was a good idea. I felt this module was really good (despite some of the naming issues I mentioned above). I’d consider taking this to the next level by utilizing the new @testSetup annotation to encapsulate your data creation in a single location. I’d also consider more complex Test Utilities classes. […]

Leave a Comment