How to set an HttpCalloutMock to reply differently on subsequent requests to the same endpoint?
This test works just fine for me:
@IsTest
class Demo
{
class Mock implements HttpCalloutMock
{
Boolean hasResponded = false;
public HttpResponse respond(HttpRequest request)
{
HttpResponse response = new HttpResponse();
response.setStatusCode(hasResponded ? 204 : 200);
hasResponded = true;
return response;
}
}
static testmethod void testMyMock()
{
HttpRequest request = new HttpRequest();
request.setEndpoint('...');
request.setMethod('GET');
Test.startTest();
Test.setMock(HttpCalloutMock.class, new Mock());
HttpResponse response1 = new Http().send(request);
HttpResponse response2 = new Http().send(request);
Test.stopTest();
system.assertEquals(200, response1.getStatusCode());
system.assertEquals(204, response2.getStatusCode());
}
}
The same test passes if you change the mock definition to:
class Mock implements HttpCalloutMock
{
Integer timesCalled = 0;
public HttpResponse respond(HttpRequest request)
{
HttpResponse response = new HttpResponse();
response.setStatusCode(timesCalled++ > 0 ? 204 : 200);
return response;
}
}
IMHO This is the way to go. Control what is returned from the test method itself by constructing the response on the fly. No need for multiple or complex mock classes with this
Since question is not a duplicate and the answer is, just copying the answer from sfdcfox
Help on Invokable Apex Test class and @Future callout Apex test Class
Basically, you need to know about how to test HTTP callouts, and how to test future methods.
Once you've gotten that far, you'll see that the unit test would look like:
@isTest class MakeCalloutTest { // Simple echo callout class // Returns whatever response we tell it to when asked class EchoHttpMock implements HttpCalloutMock { HttpResponse res; EchoMock(HttpResponse r) { res = r; } // This is the HttpCalloutMock interface method public HttpResponse respond(HttpRequest req) { return res; } } @isTest static void test() { // Avoid using live data List<Lead> leads = new List<Lead>{ new Lead(LastName='Test',Company='test') }; insert leads; // We tell it what to simulate HttpResponse res = new HttpResponse(); res.setBody('<?xml version="1.0" encoding="utf-8"?><root U_Id="12345"></root>'); res.setStatusCode(200); // This allows the callout to succeed Test.setMock(HttpCalloutMock.class, new EchoHttpMock(res)); // Start the test Test.startTest(); // Enqueue the future call MakeCallout.invokeleadcallout(leads); // Trigger future method Test.stopTest(); // Verify logic leads = [select id__c from lead]; System.assertEquals('12345', leads[0].Id__c); } }
Note: This doesn't cover the "catch" part of your try-catch block. Once you've gotten as far as covering most of your code, the catch block should be pretty simple (hint: you can construct and throw CalloutException manually from a HttpCalloutMock).
Credit to sfdcfox