Proper Unit Test Structure in Apex

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.

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.

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.

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:

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.

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.

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.

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.

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.

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.

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:

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:

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.

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)

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:

Trackbacks/Pingbacks

[…] 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. […]

[…] 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 […]

[…] 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. […]