Search code examples
unit-testingsalesforceapex-code

How to I unit test a @future method that uses a callout?


I have a trigger that fires when an opportunity is updated, as part of that I need to call our API with some detail from the opportunity.

As per many suggestions on the web I've created a class that contains a @future method to make the callout.

I'm trying to catch an exception that gets thrown in the @future method, but the test method isn't seeing it.

The class under test looks like this:

public with sharing class WDAPIInterface {
    public WDAPIInterface() {

    }

    @future(callout=true) public static void send(String endpoint, String method, String body)  {
        HttpRequest req = new HttpRequest();
        req.setEndpoint(endpoint);
        req.setMethod(method);
        req.setBody(body);

        Http http = new Http();
        HttpResponse response = http.send(req);

        if(response.getStatusCode() != 201) {
            System.debug('Unexpected response from web service, expecte response status status 201 but got ' + response.getStatusCode());
            throw new WDAPIException('Unexpected response from web service, expecte response status status 201 but got ' + response.getStatusCode());
        }
    }
}

here's the unit test:

@isTest static void test_exception_is_thrown_on_unexpected_response() {
    try {
        WDHttpCalloutMock mockResponse = new WDHttpCalloutMock(500, 'Complete', '', null);
        WDAPIInterface.send('https://example.com', 'POST', '{}');
    } catch (WDAPIException ex) {
        return;
    }

    System.assert(false, 'Expected WDAPIException to be thrown, but it wasnt');
}

Now, I've read that the way to test @future methods is to surround the call with Test.startTest() & Test.endTest(), however when I do that I get another error:

METHOD RESULT 
test_exception_is_thrown_on_unexpected_response : Skip

 MESSAGE 
Methods defined as TestMethod do not support Web service callouts, test skipped

So the question is, how do I unit test a @future method that makes an callout?


Solution

  • The callout is getting skipped because the HttpCalloutMock isn't being used.

    I assume that WDHttpCalloutMock implements HttpCalloutMock?

    If so, a call to Test.setMock should have it return the mocked response to the callout.

    WDHttpCalloutMock mockResponse = new WDHttpCalloutMock(500, 'Complete', '', null);
    Test.setMock(HttpCalloutMock.class, mockResponse);
    WDAPIInterface.send('https://example.com', 'POST', '{}');
    

    Incidentally, the Salesforce StackExchange site is a great place to ask Salesforce specific questions.