2

After a bunch of research, it appears this is not possible, but I'm hoping someone here has found a way.

I am using a before update trigger on Opp to call a class which contains a future method with an HTTP callout. It all works fine. But in the test class, Limits.getCallouts() always returns 0.

Test.startTest();       
        update Opportunities;
        Integer callouts = Limits.getCallouts();
        system.debug('Callouts = '+callouts);
Test.stopTest();

The debug always shows 0, even though the debug log also shows that the callout was indeed made. I am successfully getting the response from my mock callout class.

USER_DEBUG [29]|DEBUG|Successful message sent, response: Thanks for all the fish!

USER_DEBUG [39]|DEBUG|Callouts = 0

This is always the case, whether I put the debug before stopTest, after stopTest, or even if I don't use start/stopTest at all.

How can one ever test the number of callouts they've made in a test class?

6

Typically, if I want to verify the callout is made and there may be asynchronous processing involve, I just track it on my mock.

class MyMock implements HttpCalloutMock
{
    Integer calls = 0;
    public HttpResponse respond(HttpRequest request)
    {
        calls++;
        // mock implementation here
    }
}

Then, in your test, you just cache your mock instance and assert against that.

MyMock mock = new MyMock();
Test.setMock(HttpCalloutMock, mock);

Test.startTest();
    // do stuff which invokes callout
Test.stopTest();

system.assertEquals(1, mock.calls, 'The mock should be called');
  • 1
    If you are teating a future method, you can't verify limits consumption. – Adrian Larson Sep 24 at 2:44
  • @AdrianLarson I just realized you could check the limits inside the mock. Nifty. – sfdcfox Sep 24 at 2:56
  • Yes, the test class tests a future method that does the callout - so the above will not work to test either? – JSF Sep 24 at 21:47
  • Yes it will. Try it out. If the callout is made your mock will increment. The reason you can't test directly is the code only runs when you call stopTest. But that resets limits so you can't verify a call was made. – Adrian Larson Sep 24 at 23:35
  • Thanks for this, yes that works out. I do believe that Integer calls needs to be public though. Interesting that Test.setMock does not actually run the mock, I always assumed it did, which would mean the test class wasn't actually testing any real code. But sure enough this only passes when the "do stuff" invokes the callout. Thanks – JSF Sep 25 at 5:51
0

It turns out to be zero because (a) the future method is not called until Test.stopTest(), and (b) immediately after Test.stopTest(), you go back in to the test's governor limits. In addition to Adrian's suggestion, you could also have a "universal" method that does the actual callout and provides a nice hook for consistent monitoring:

public class HttpCallout {
  @TestVisible static Integer calloutCounter = 0;
  public static HttpResponse doCallout(HttpRequest req) {
    calloutCounter++;
    return new Http().send(req);
  }
}

Other variants are possible, but this gives you an easy framework to manage this info. As a bonus, you could add try-catch logic, error logging, etc to provide a consistent API that your team can use for callouts.

Adrian's solution is also perfectly serviceable, I just prefer something that can be reused consistently and provide a "service layer" interface to callouts.


Edit: I just realized you can also test the limits inside the mock. Since this is already only used for unit tests, this should work just as well.

@isTest class q279143 {
    public class Mock implements HttpCalloutMock {
        public HttpResponse respond(HttpRequest req) {
            System.assertEquals(1, Limits.getCallouts());
            return new HttpResponse();
        }
    }
    @future(callout=true) static void method() {
        HttpRequest req = new HttpRequest();
        req.setMethod('GET');
        req.setEndpoint('https://www.google.com/');
        new Http().send(req);
    }
    @isTest static void test() {
        Test.startTest();
        Test.setMock(HttpCalloutMock.class, new Mock());
        q279143.method();
        Test.stopTest();
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.