A Pattern for Portable Apex Unit Tests
(If you’re just interested in seeing my suggestion for an Apex Testing Pattern, check out the last two code snippets. For an adventure through dev experience and justification for the need of a pattern, read on.)
Force.com is a multi-tenant platform, so if your code is running rampant, your neighbors will feel its wrath. It only makes sense that Salesforce requires developers on its platform to write unit tests. When refactoring code, unit tests will tell you when something breaks. You may find that writing your unit tests for a piece of code is too difficult, which is a sign that your design is too complex and will be unwieldy when debugging at later time or by someone else. There are pitfalls when using any unit test framework, but I want to take some time to highlight a few of the more sinister pitfalls that will be invisible to you until you fall into them head-first.
Field requirements change.
The first common design oversight is not keeping in mind the fact that field requirements may change. It’s inevitable during the growth and refining of any Salesforce org, if not every software application, that requirements change. This could be that older objects have new fields, new required fields, or changed field definitions. This is fine, right? You aren’t hard-coding object creation into each and every unit test, are you? What’s that? To shreds, you say? Well, if you do hard-code sObject creation in your unit tests, then you’re probably in the majority, so don’t worry, it’s definitely the most direct and simple way to write them. Let’s see how that would look:
static testMethod void testCreateMyObject_shouldSucceed() {
//Create test data
MyObject__c object1 = new MyObject__c(Name = 'TestName', MyField__c = 50);
//Invoke functionality
Test.startTest();
String errorMessage = '';
try {
Database.insert(object1);
catch (DmlException e) {
errorMessage = e.getMessage();
}
Test.stopTest();
//Check results
System.assertEquals('', errorMessage);
}
This looks fine, right? It sure does, so let’s copy and paste this unit test about thirty times to test for the various edge-cases. Cool. Now fast-forward a few months to when MyObject__c gets MyField2__c added to it and made to be a required field. Ka-boom! Time to rewrite thirty unit tests!
Moving code to a different org.
Some developers will have to package their code and move it to a different org. If you are one of these developers, I’m sure you’ve had a multitude of issues with this before. You’ve got your code working great in your sandbox org, and then applied some fixes after discovering that your code doesn’t account for running in an empty org and can’t handle a few measly null references. After that experience, you’ll be a little nervous when it becomes time to install it into a production org, or worse, a production org with complex workflows and triggers.
Fears coming true, when installing your wonderful package of joy into the production org, you find that your code may be trying to insert a standard Contact record with the bare minimum number of fields and the Contacts that are being inserted by your unit tests are being rejected. How could you know that the installing org decided to make Contact.FavoriteCRMSoftware__c a required field! Time to rewrite some unit tests!
Force.com Portable Tests Pattern
So what’s a dev to do? Now that we have the foresight, what can we do to evade these errors and save ourselves some unit test re-writing? Thinking about it, we find the crux to be this question: How can we successfully insert data when we don’t know the conditions for successful insertion at design time?
The suggested answer: For most cases, isn’t it enough to query for an existing record in the database to use? That record is in the org, so it must already have the information required by the org. So grab one, modify the record to the state that your test needs, and go with it. If you need to test insertion, this probably won’t work (though maybe you could query for a record, and set the ID of the returned record to null, then insert it as a new record. Hmm…).
I postulate that the best solution for these issues is to use the following Force.com Portable Tests Pattern (please suggest a better name). It uses a TestObjects class that acts as a kind of record factory that abstracts away an individual unit test’s responsibility for creating/querying for a record to use in your test. Check out how we would change the example above:
static testMethod void testCreateMyObject_shouldSucceed() {
//Create test data
//Invoke functionality
Test.startTest();
String errorMessage = '';
try {
//This method creates and inserts it for us. We could also use the createMyObject method in this case.
MyObject__c object1 = TestObjects.getMyObject();
catch (DmlException e) {
errorMessage = e.getMessage();
}
Test.stopTest();
//Check results
System.assertEquals('', errorMessage);
}
And then use a TestObjects class that will handle the creation/querying for a record to use:
public with sharing class TestObjects {
//Use the get* method if you want to do the query-first object creation.
public static MyObject__c getMyObject() {
MyObject__c myObject = new MyObject__c();
try { //Try to query for the desired record first.
myObject = [SELECT Name, MyField__c FROM MyObject__c LIMIT 1];
}
catch (QueryException e) { // If that fails, then create one.
myObject = TestObjects.createMyObject('TestFeature', 50);
}
return myObject;
}
//If you want to skip the query-first part, just call the create* method.
//If you discover a required field in the org, you only need to change this method, not every single unit test.
public static MyObject__c createMyObject(String name, integer myField) {
MyObject__c myObject = new MyObject__c(
Name = name,
MyField__c = myField);
Database.insert(myObject);
return myObject;
}
}
What do you think of this structure? Do you see anything I’m missing? Can it be made more robust? Should we change the name of the TestObjects class to something else? Leave a comment below.
EDIT: There are also a few good comments on my Google+ post, expressing doubt with relying on org data, among other things. Circle me if you’re interested. Link to my profile here.
Don't miss any posts! Subscribe to our blog feed or only posts by Alex Berg.
Short URL: http://sundoginteractive.com/e/4141

Comments
Interesting post Alex. The way I have always dealt with this is to include static methods in my test classes that create the data needed for a particular set of tests. I have also worked in a team that did similar to yourself and defined a series of classes that created test data. The debate is around whether a single set of test data or a set of test data per test class is better.
From a pure TDD perspective, I would argue having a set of data methods in each test class is better because you are then only testing changes to the system that effect the functionality being tested. It also allows you to create data specific to the test and not large amount of surrounding data (you could find that having a single method to create an object could lead to a large amount of unrequired extra work causing tests to run slower).
On the reverse is the fact that all the data used throughout every test is consistent and full and can also be run as a series of methods to be used in manual testing and demonstrations (just invoke all of the data creation methods).
On a piece of separated code (e.g. consultancy or a component or internal system) then a set of methods in each test class is probably more beneficial. If I were working on a product suite, I would adapt your method to use it as previously described to provide demo data etc.
Great post though still. And TestObjects is a fine name. You should also look at SmartFactory as I believe it is similar.
I’ve been planning an extended set of regressions tests for my orgs and how to generate test data has been an ongoing challenge for exactly the reasons you elucidate. I’ll be using methods to create records at various stages in the lifecycle depending on the test needs. At least then there’ll only be one method to update when someone adds validation rules without testing first!
Hey Alex, great post!
You might also be interested in this library for generating test data in Apex unit tests:
https://github.com/mbotos/SmartFactory-for-Force.com
We’d love to have you contribute to the project if you’re interested!
Good post…..good topic.
Another approach is to change TestObjects to utilize the builder pattern, which would be used something like this:
TestObjectsV02 builder = new TestObjectsV02();
MyObject__c result =
builder.withName(‘myName’)
. withMyfield(‘aField’)
.build();
This way, one can generate data specific to the test (as in TDD) but still have a central spot to maybe set some defaults on the object and, also, check for required fields. It could, again, fill in required fields with defaults.
Edwin:
Great idea! I haven’t seen an sObjectBuilder anywhere before, so I’ll see if I can apply it there. In the meantime, you should also throw your hand at it, and let us know if you come up with anything. If you’re like to collaborate, you can find me on Twitter or G+. There are links in my “about the author” box above.
Leave A Comment