5 min read

A better way to Unit Test Callouts in Apex Code

Update: In this article I describe using a singleton class to set a property that can be checked by web service methods to check if the call is being executed as part of a unit test as well as what mock response to return. While the mock response portion still holds true and I feel is an excellent way to vary your results, I also found that there is native support by Apex Code for checking if a unit test is running.

I was doing some research for a different issue entirely and came across the system test methods section in the Apex Code documentation for the Winter 11 release. In it is a method called isRunningTest that indicates if a test is running. I don't know when this was added or how long it has been available but this is definitely the better option for your code to determine if it should respond differently based on unit testing.

The syntax really simple:

if (Test.isRunningTest()) {
     //unit testing alternative code goes here
}
else {
     //execute normally
}

I have integrated Salesforce with a number of external web services. The integrations usually go pretty smoothly but one part that has always seemed to be a pain is unit testing. The traditional method is to generate your proxy classes, write your code to implement them with a switch of some sort near where the callout takes place in order to skip making the actual callout (which is not allowed during unit testing).

So this meant that I had to make all of my classes aware of when my code was executing as part of a unit test. If the solution was complex enough and incorporated multiple layers of classes I would have to add a property to each class and propagate that through the call chain; and hope I didn't miss any. This proved to be a maintenance nightmare and I felt was just too risky of a solution.

I had to come up with a better way.

For a while now, I have been playing around with a utility class for my unit tests. Specifically, the idea was to create a class with methods that could generate instances of SObjects with any required fields already populated. This need came from maintaining a pretty large code base and trying to keep the unit tests maintained as new rules were implemented in to the system. This could range from changes to validation rules, workflows, and/or triggers that applied specific business validation logic.

In many cases, the issue was as simple as a System Administrator adding a validation rule and while it did not break the system or the code it would break my tests. So the issue usually wasn't identified until we run all unit tests or started a deployment process to production, which runs all tests by default.

Account validation changes are a good example of a simple change causing a big issue for your unit tests, because just about everything in Salesforce starts with an account. So think about all of the tests in the system that create an account to hang contacts, activities, opportunities, etc. on to. Now imagine all those tests breaking because of one validation rule and having to go in and update all of those test methods. In our environment, this is especially tricky because we have compliance and auditing to account for when modifying anything in the system. So going in and updating a bunch of classes in mass had its consequences.

So, with all this in mind I created a helper class in the form of the UnitTestUtil class. This class was basically a collection of methods that would create instances of classes and if new validation rules were added I could modify these methods and all of my unit tests that utilized this class for SObject instance generation would start to work again.

I then realized that this UnitTestUtil class could do something more. If I implemented it using a Singleton pattern I could allow the unit test utility class to let my callout methods know whether or not I was performing a unit test or not. This had an added benefit of solving another issue that I had, which was providing variable mock callout responses to enrich my testing scenarios.

So lets take a look at the UnitTestUtil class and then take a look at how it can be used.

public class UnitTestUtil {
    private static UnitTestUtil oUnitTestUtil;
    
    public boolean IsUnitTesting {get;set;}
    public object MockWebServiceResponse {get;set;}
    
    private UnitTestUtil() {
        IsUnitTesting = false;
        MockWebServiceResponse = null;
    }
    
    public static UnitTestUtil getInstance() {
        if (oUnitTestUtil == null) {
            oUnitTestUtil = new UnitTestUtil();
        }
        
        return oUnitTestUtil;
    }
    
    public Account getAccountInstance() {
        Account oAccount = new Account();
        oAccount.Name = 'Unit Test Account';
        
        return oAccount;
    }
    
    public Contact getContactInstance() {
        Contact oContact = new Contact();
        oContact.FirstName = 'Unit';
        oContact.LastName = 'Tester';
        oContact.Email = 'unit.tester@email.com';
        
        return oContact;
    }
    
    public Opportunity getOpportunityInstance() {
        Opportunity oOpportunity = new Opportunity();
        oOpportunity.Name = 'Unit Test Opportuntiy';
        oOpportunity.CloseDate = System.Today() + 5;
        oOpportunity.StageName = 'Prospect';
        
        return oOpportunity;
    }
}

As you can see from the code above the class is pretty simple. It has a get instance method which first checks if a static instance of the utility class exists and if not it creates a new instance and returns that instance. You will also notice a couple of helper methods for creating instances of SObjects with some default fields set.

There are not any insert statements for these methods. The goal is only to return a valid instance and let the test method decide how and when to perform the insert. This allows the developer the ability to properly create the record either as part of the unit test setup or as part of the actual test itself.

So now that we have seen the class lets see how it can be used. Below is an example of how this can be used in a callout method. Notice that I am casting the mock response to a string. This is because the mock response is an object allowing you to cast the response to the datatype that your callout would normally return, which more often than not will be a response class of some sort.

public string myCalloutMethod() {
    string sResponse = '';

    UnitTestUtil oUtil = UnitTestUtil.getInstance();
    if (oUtil.IsUnitTesting) {
        sResponse = (string) oUtil.MockResponse;
    }
    else {
        //Perform callout
        sResponse = HttpCallout.Execute(); //Not a real callout method it is just for illustration purposes
    }

    return sResponse;
}

As you can see if the unit test utility class indicates that this call is part of a unit test then it returns the mock response defined in the utility class. This allows me to vary the response based on the type of testing I want to do. I now have the option to test a perfect world response or an imperfect one. It should also help improve code coverage results since you will be able to return a response that can be used by any post-callout processing methods and you can vary the response to handle any logic that you have implemented based on the response, such as success, failures, or specific response types.

The unit test method would look similar to below:

public static testmethod void testMyCallout() {
    UnitTestUtil oUtil = UnitTestUtil.getInstance();
    oUtil.IsUnitTesting = true;
    oUtil.MockResponse = 'My Perfect World Response';
    
    Test.startTest();
    
    string sResponse = myCalloutMethod();
    System.assert(sResponse == oUtil.MockResponse, 'Expected perfect world results');
    
    oUtil.MockResponse = 'My Imperfect World Response';
    string sResponse = myCalloutMethod();
    System.assert(sResponse == oUtil.MockResponse, 'Expected imperfect world results');
    
    Test.StopTest();
}

Overall, it is a pretty simple solution to a problem that has been a pain to address in the past. I have only just started working with this solution so I haven't had a chance to identify any pitfalls, issues, bugs, etc. but if you decide to implement this for your own projects please let me know how well it does or if you have any suggestions for improvement.