The Winter ’13 release added a couple of new features for testing Apex callouts. Specifically, developers can now either
- Use a Static Resource to save the test response (e.g. a JSON text file) and then use the StaticResourceCalloutMock or MultiStaticResourceCalloutMock system classes to test one or more callouts, or
- Implement one of two new interfaces: HttpCalloutMock, for HTTP (REST) callouts, or WebServiceMock, for Web Service (SOAP) callouts
Pat wrote an excellent blog post breaking down the first option. Lets review the second option, specifically how to implement the HttpCalloutMock interface to test HTTP callouts.
Testing a single HTTP callout
Lets start with a relatively simple requirement of testing an Apex class that makes a single HTTP (i.e. REST) callout. Here’s the code that we need to test.
The first step is to create a class that implement the HttpCalloutMock interface.
Note: While it is not required to mark your HttpCalloutMock implementation class as @isTest, it is generally a best practice to do so in order to exclude the class from your organization’s code size limit of 3 MB.
You need to implement the ‘respond’ method of the HttpCalloutMock interface in which you return a fake HttpResponse. As you can see, we’ve created a utility testing class that can be used to test any scenario that involves a single HTTP callout, and not just the CalloutAccounts class shown earlier. This utility class can be used to test both binary and String responses (depending on which constructor you use to instantiate the class) and also lets you specify the HTTP code and status for the fake response. You can optionally also specify HTTP headers to be included in the fake response. Next, lets see how we use this HttpCalloutMock implementation to test our CalloutAccounts class.
Line 8 shows how we use the Test.setMock system method to tell the platform which HttpCalloutMock implementation to use during the test. After that line, if an HTTP callout is invoked in test context (e.g. the callout code in our CalloutAccounts.getAccounts method), the callout is not made and you receive the mock response specified in the ‘respond’ method implementation.
Testing multiple HTTP callouts
Lets make things a little more complicated now. Say that your code makes multiple HTTP callouts in a single transaction. Here’s a simple example from Pat’s blog post
Here, we’re making two callouts, one to retrieve the Account data and another to retrieve the Contact data. Using the SingleRequestMock class that we had created above doesn’t work since that class returns the same fake HttpResponse for every callout. One option is to use Static Resources and the MultiStaticResourceCalloutMock
class shown in Pat’s blog to return different fake responses based on the HTTP endpoint being invoked. However, that approach cannot handle cases where you need to test for dynamic response data with dependencies on query parameters and/or the request body. Also, what about cases where your code expects a binary response from one callout (e.g. a callout to the Google Map API) and a text/JSON response from another callout. Even though our simple code sample above does not meet either of those two criteria, lets see how we can use HttpCalloutMock to test it.
Like our SingleRequestMock utility, the class above also implements the HttpCalloutMock interface. However, unlike SingleRequestMock, this class is simply a wrapper that maintains a Map of HTTP endpoints –> their dummy HttpCalloutMock implementations. Lets see how we can use this utility class to test our multiple callout code.
In the test method above, we first construct the fake test responses for our two callouts on lines 4-12 using the SingleRequestMock utility class. We then create a Map of the two HTTP endpoints to their respective fake responses and instantiate a MultiRequestMock object out of that. Finally, we use Test.setMock to tell the platform to use the MultiRequestMock object for every HTTP callout made in a test context from that point onward. When we execute our processAccountsContacts code, the ‘respond’ implementation in the MultiRequestMock class will return the appropriate fake response depending on the endpoint being invoked.