Test Class for Apex methods making Callouts
Methods defined as TestMethod do not support Web service callouts. This is the error that you will encounter when you run a test for an Apex class that makes a callout. The error being quite descriptive, it becomes obvious that you cannot directly test and/or have a coverage for the piece of code that makes a callout. To fix this we have 2 options. First one is a quick hack where you skip callout and set a mock response. The second option also involves mocking but instead of straightaway mocking the response, we mock the endpoint for callout
Option#1 - Test.isRunningTest()
So is there no way to have above 75% coverage and push such a code (that makes a callout) to production environment. Test.isRunningTest() comes to rescue. This method returns true if the currently executing code was called by code contained in a test method, false otherwise. So the workaround is simply to enclose the code blocks that are related to a Callout in an if condition as shown below.
...
HttpResponse res;
String JSONContent = '<sample JSON string of the response>';
if(!Test.isRunningTest()){
req.setEndpoint('<endpoint url>');
req.setMethod('GET');
res = http.send(req);
JSONContent = res.getBody();
}
...
The callout code will be executed only when the execution isn't from a test context; in which case the hard-coded JSON string will be used as JSON content. Make sure that you pass a real JSON string so that there is sufficient coverage without any Null pointer exceptions.
Option#2 - Implement HttpCalloutMock interface
Below is an example class that implements HttpCalloutMock
interface. The interface consists of just one method respond
that accepts HttpRequest
as parameter and returns HttpResponse
. The method need no implement the functionality of the actual endpoint but just need to mock it. And thereby set the status code and response body accordingly.
global class MyCalloutMock implements HttpCalloutMock{
global HttpResponse respond(HTTPRequest req){
HttpResponse res = new HttpResponse();
res.setStatus('ok');
res.setStatusCode(200);
res.setBody('<json string>');
return res;
}
}
The next step after this is tell the test class to make the test method hit the mock endpoint instead of the actual one. We do this by the following code snippet.
Test.startTest();
Test.setMock(HttpCalloutMock.class,new MyCalloutMock());
Test.stopTest();
The rest of the test method can have the blow code to set the HttpRequest
and HttpResponse
context and optionally URL parameters before getting the actual callout apex code executed.
String baseUrl = URL.getOrgDomainUrl().toExternalForm();
RestRequest request = new RestRequest();
RestResponse response = new RestResponse();
request.requestUri = baseUrl + '<optional uri>';
request.params.put('<some key>', '<some value>');
request.httpMethod = 'GET'; //or other HTTP methods
RestContext.request = request;
RestContext.response = response;
// Call your class code that has the callout code;
System.assert(RestContext.response.responseBody,'<expected response>');