I’m sure every Apex developer has had their Developer Org data interfere with their unit testing. Or perhaps you have coded unit tests that function perfectly within your Developer Org but when deployed to another Org fail because of a different, partial or empty database.
Of course as a developer this type on inconsistency within your work environment is extremely counter-productive. Initially I developed a methodology that did the job but wasn’t nearly as concise as I would have liked. More recently however I’ve developed a technical solution that is universal as well as quick to implement.
Let’s consider the following scenario
- Your application uses a custom object called MyObject__c.
- A record of this object type, with a specific name must exist for your application to function correctly(You create this record post-package installation).
- Your Developer Org has a record with this name and trying to create another one would throw an exception due to a uniqueness constraint.
- The Org you are deploying to will not have this record initially.
In order to cater for both situations within my unit tests i.e. a record existing in one Org but not in another, I might have coded the unit test data initialisation like this
MyObject__c obj;
try{
obj = new MyObject__c(name=’theOne’);
insert obj; // Try to insert he object record
}catch(System.DMLException e){
obj = [SELECT id, name FROM MyObject__c WHERE name = ‘theOne’]; // If the record exists fetch it from the DB
}
This worked for me, but it’s a messy solution at best, and if you require records from 10 objects to exist for a single unit test, your data initialisation becomes unnecessarily complex and difficult to read.
“Work smart not hard.” my grand-pappy said, so I sat back and had a think. The situation in each unit test was similar, as was the solution.. and when that happens every developer knows it’s an opportunity to develop a smart, simple and reusable solution. It was in developing a static utility class to solve the frustrating ‘Mixed DML Exception’ that the solution became obvious – use a utility class to clear the database before any specific data initialisation you may require. For the above example I might code a utility class like this,
public Class UnitTestUtil{
public static void clearDatabase(){
List<MyObject__c> myObjects = [SELECT id FROM MyObject__c];
delete myObjects;
List<… // Clear the rest of the database
}
}
And your unit tests might start thus,
static testMethod void myTest(){
UnitTestUtil.clearDatabase();
MyObject__c obj = new MyObject__c(name=’theOne’);
insert obj;
… // Rest of data init happens here
… // Actual testing
}
I like this solution because it’s simple to read and understand, and reduces the amount of code you need to write.. and who wants to write more code than necessary. Something to consider is that for any objects related by a master-detail relationship you should only need to delete the parent record, as it will cascade for any children. Also note that the Delete commands that you issue will only remove data from the context of the unit test in question i.e. if your Org contains records of type MyObject__c, the above code would delete the records making them unavailable to the unit test code, but that data would return after the execution of the test code completed. Weird huh?
Unit testing sucks, but it is undeniably necessary, and if anyone has any tricks to help the community at large drop me a mail or write an article, after all, that which benefits one benefits us all.