I am facing a issue with my mock class where I am suppose to create a mock class for a class that makes several callouts in a single method based on criteria's. Now , when I am trying to create a mock class then it is only acting for the first callout but others callouts are not getting handled.How to work with these classes.
3 Answers
Here is perhaps the simplest form of a mock that deals with multiple requests.
It is declared as an inner class of the test class so the idea is that it handles all the cases that the outer test class handles. In the respond
method you can look at the endpoint of the request or the body of the request and use if/else logic to return the appropriate fake response. (You can also add asserts to verify the details of the request body.)
@IsTest
private class CalloutTest {
private class Mock implements HttpCalloutMock {
public HTTPResponse respond(HTTPRequest req) {
if (req.getEndpoint().endsWith('abc')) {
HTTPResponse res = new HTTPResponse();
res.setBody('{}');
res.setStatusCode(200);
return res;
} else if (req.getEndpoint().endsWith('xyz')) {
...
} else {
System.assert(false, 'unexpected endpoint ' + req.getEndpoint());
return null;
}
}
}
@IsTest
static void abc() {
Test.setMock(HttpCalloutMock.class, new Mock());
...
}
@IsTest
static void xyz() {
Test.setMock(HttpCalloutMock.class, new Mock());
...
}
}
-
2
-
1@AdrianLarson Only if you overlook that the map values have to be other HttpCalloutMock implementations.– Keith CSep 1, 2016 at 17:22
This need is covered in Testing Apex Callouts using HttpCalloutMock. Specifically, see the Testing multiple HTTP callouts section. Here's the example they use:
public class MultiRequestMock implements HttpCalloutMock {
Map<String, HttpCalloutMock> requests;
public MultiRequestMock(Map<String, HttpCalloutMock> requests) {
this.requests = requests;
}
public HTTPResponse respond(HTTPRequest req) {
HttpCalloutMock mock = requests.get(req.getEndpoint());
if (mock != null) {
return mock.respond(req);
} else {
throw new MyCustomException('HTTP callout not supported for test methods');
}
}
public void addRequestMock(String url, HttpCalloutMock mock) {
requests.put(url, mock);
}
}
I'm not sure why they don't annotate the class as @IsTest
. You probably should.
I've created a generic "utility" class that makes this much easier to do (and all HTTP testing in general).
Basically the setup looks like this:
MockHttpResponseHandler.SimpleMockResponse getResp = new MockHttpResponseHandler.SimpleMockResponse('GET', getResponse);
MockHttpResponseHandler.SimpleMockResponse errResp = new MockHttpResponseHandler.SimpleMockResponse('GET', null);
errResp.statusCode = 500;
MockHttpResponseHandler mock = new MockHttpResponseHandler();
mock.addResponse(testEndpoint, getResp);
mock.addResponse(testEndpoint, getResp);
mock.addResponse(testEndpoint, errResp);
// when hitting GET:testEndpoint, 'getResp' will be returned twice. All additional calls will return 'errResp'
It also allows much more dynamic functionality if needed through custom implementation.
Check out the repo readme for full details on how it works.