Testing Single HttpCalloutMock in Apex is pretty straightforward which is described in official docs. If you want to test multiple callout then here is the official docs. So You need to prepare related code base whenever you've something new to test. What if we don't need to write this almost the same code repeatedly? Let's try to design a class that will serve our purpose, that way we don't have to repeat ourselves anymore.
Class: GlobalMock.cls
public class GlobalMock implements HttpCalloutMock {
public List<Map<String, String>> records {get;set;}
public GlobalMock(List<Map<String, String>> records) {
this.records = records;
}
public GlobalMock(Map<String, String> sampleMockMap) {
this.records = new List<Map<String, String>>();
this.records.add(sampleMockMap);
}
public GlobalMock(String endpoint, String method, String body) {
Map<String, String> sampleMockMap = new Map<String, String>();
sampleMockMap.put('endpoint', endpoint);
sampleMockMap.put('method', method);
sampleMockMap.put('body', body);
this.records = new List<Map<String, String>>();
this.records.add(sampleMockMap);
}
public HttpResponse respond(HttpRequest req){
HttpResponse res=new HttpResponse();
res.setHeader('Content-Type','application/json');
res.setStatusCode(200);
for (Map<String, String> record: this.records) {
if (req.getEndpoint().contains(record.get('endpoint'))) {
if (record.get('body') != null) res.setBody(record.get('body'));
System.assertEquals(record.get('method'), req.getMethod());
}
}
return res;
}
}
Just a regular class that will behave/respond based on your input. By using this class we can test our HttpCallout without ever writing separate code specific for HttpCallout. As you can see the GlobalMock class has three different types of constructors, we can test the HttpCallout in three different ways.
- Testing a single endpoint by passing constructor values as strings, in a single line.
Test.setMock(HttpCalloutMock.class, new GlobalMock('https://abc.com/api/v1/token/', 'POST', '{"success":"true"}'));
- Testing a single endpoint by passing the constructor value as a Map.
Map<String, String> sampleMockMap = new Map<String, String>();
sampleMockMap.put('endpoint', 'https://abc.com/api/v1/token/');
sampleMockMap.put('method', 'POST');
sampleMockMap.put('body', '{"access":"test"}');
Test.setMock(HttpCalloutMock.class, new GlobalMock(sampleMockMap));
- Testing multiple endpoints by passing constructor value as a List of Map.
List<Map<String, String>> sampleMockList = new List<Map<String, String>>();
Map<String, String> sampleMockMap = new Map<String, String>();
sampleMockMap.put('endpoint', 'https://abc.com/api/v1/status/123/delete/?is_instructor=true');
sampleMockMap.put('method', 'DELETE');
sampleMockList.add(sampleMockMap);
Map<String, String> sampleMockMap1 = new Map<String, String>();
sampleMockMap1.put('endpoint', 'https://abc.com/api/v1/status/?customer_id=');
sampleMockMap1.put('method', 'GET');
sampleMockMap1.put('body', '{"count":4,"next":null,"previous":null,"results":[{"id":"d220-9ab6-d5ad3460","customer_id":"123"}]}');
sampleMockList.add(sampleMockMap1);
Map<String, String> sampleMockMap2 = new Map<String, String>();
sampleMockMap2.put('endpoint', 'https://abc/api/v1/token/');
sampleMockMap2.put('method', 'POST');
sampleMockMap2.put('body', '{"access":"test"}');
sampleMockList.add(sampleMockMap2);
Test.setMock(HttpCalloutMock.class, new GlobalMock(sampleMockList));
If you see any pitfalls or if you've any better ideas, please feel free to put your observations.
Comments (0)