I’m initiating a new routine of weekly blog posts, beginning with advice on crafting a versatile class or a mock factory to simulate interactions with an external third-party service.
What’s the rationale behind using a mock
When running unit tests the platform does not allow to do a callout to external dependencies. To test our code base we would need to mock the response as if calling the third party dependency.
By mocking we focus on the code being tested, isolating it from the state and behavior of the external system. The dependencies are simulated and the output state can be controlled.
To start we create a class that implements the HttpCalloutMock. This class enables sending a fake response when doing HTTP callouts. When our code makes a callout, the response will come from our HttpCalloutMock class.
When creating the class we define the constructor and parameters. We can make it generic and serve as a mock factory. Instead of writing several mock classes for every type of response, we only write it once which promotes code reusability best practices. And during unit testing, we define the mock response on the fly.
Here is our sample class which implements the HttpCalloutMock.
public with sharing class GenericRESTMock implements HttpCalloutMock{ protected Integer code; protected String status; protected String body; protected Map<string , String> responseHeaders; public GenericRESTMock(Integer code, String status, String body, Map<String,String> responseHeaders) { this.code = code; this.status = status; this.body = body; this.responseHeaders = responseHeaders; } public HTTPResponse respond(HTTPRequest req) { //create fake response HttpResponse res = new HttpResponse(); for (String key : this.responseHeaders.keySet()) { res.setHeader(key, this.responseHeaders.get(key)); } res.setBody(this.body); res.setStatusCode(this.code); res.setStatus(this.status); return res; } }
And if we have a class that does an HTTP Callout and we want to write a unit test for it. This is how it going to look like.
public with sharing class MyServiceAPI { @AuraEnabled public static String getTransactions(String dateFrom) { HttpRequest req = new HttpRequest(); req.setMethod('GET'); //retrieved from named credentials request.setEndpoint('callout:MyServiceAPI/transactions?date=dateFrom'); req.setEndpoint(strEndPoint); req.setHeader('Accept', 'application/json'); Http h = new Http(); HTTPResponse res = h.send(req); if (res.getStatusCode() == 200) { return res.getBody(); } return null; } }
This is how we would create a unit test.
@isTest private class MyServiceAPITest { @isTest static void getTransactionsTest() { Test.startTest(); Map<String,String> headers = new Map<String, String>(); headers.put('Accept','application/json'); Test.setMock(HttpCalloutMock.class, new GenericRESTMock(200,'Success','{"Items":[{"Id":"string","Code":"string","EffectiveDate":"2019-07-15T22:03:31.145Z","Type":"APP"]}',headers)); String str = MyServiceAPI.getTransactions('7/15/2019'); Test.stopTest(); system.assertEquals(null, str); } }
Key Takeaways
- Use named credentials when possible when doing HTTP Callouts. Will talk about this more in the future.
- When writing the unit test, the key is to call Test.setMock() which makes sure any callout from your code will return the Mock object.
- Define the mock response on the fly to test different response.
Hope you find this useful. Stay tuned for more coding content and tips. If interested in the source code it is available in GitHub.