[SalesForce] “Methods defined as TestMethod do not support Web service callouts” error when testing apex callout

I am trying to write a test for a trigger that is firing a future apex callout :

The trigger calls the callBillingService method from this class:

public class BillingCalloutService {
    //Implement business and callout logic methods here
    @Future(callout=true)
    public static void callBillingService(List<Id> recordIds) {
        List<Project__c> projects = [Select Id, ProjectRef__c,Billable_Amount__c from Project__c Where Id = :recordIds];

        List<Project__c> projectsToUpdate = new List<Project__c>();

        String username = ServiceCredentials__c.getValues('BillingServiceCredential').Username__c;
        String password = ServiceCredentials__c.getValues('BillingServiceCredential').Password__c;

        String auth = username + ':' + password;
        String encodedAuth = EncodingUtil.base64Encode(Blob.valueOf(auth));

        for(Project__c p : projects) {

            BillingServiceProxy.InvoicesPortSoap11 service = new BillingServiceProxy.InvoicesPortSoap11();
            service.inputHttpHeaders_x = new Map<String, String>();
            service.inputHttpHeaders_x.put('Authorization', 'Basic ' + encodedAuth);

            BillingServiceProxy.project project = new BillingServiceProxy.project();
            project.username = username;
            project.password = password;
            project.projectRef = p.ProjectRef__c;
            project.billAmount = p.Billable_Amount__c;

            if(service.billProject(project).equals('ok')){
                projectsToUpdate.add(new Project__c(ProjectRef__c = p.ProjectRef__c, Status__c = 'Billed'));
            }
        }
        shouldIRun.stopTrigger();
        upsert projectsToUpdate ProjectRef__c;
    }
}

Error

Methods defined as TestMethod do not support Web service callouts

Test Class

@IsTest
private class BillingCalloutServiceTest {

    @IsTest
    private static void testBillingCalloutService() {
    Account a = new Account(Name = 'Acme');
    insert a;
    Opportunity o = new Opportunity(Name='Test', StageName='Submitted Project', AccountId=a.Id, Amount=1000, CloseDate=Date.Today());
    insert o;
    Project__c p = new Project__c(Status__c='Running',Start_Date__c=Date.Today(),End_Date__c=Date.Today(),Billable_Amount__c=10000,ProjectRef__c='projectX',Opportunity__c=o.Id);
    insert p;

    insert new ServiceCredentials__c(Name='BillingServiceCredential',Username__c='toto', Password__c='azerty');

    Test.startTest();
    Test.setMock(HttpCalloutMock.class, new BillingCalloutServiceMock());
      p.Status__c = 'Billable';
      update p;
    Test.stopTest();
    // runs callout and check results
    p = [select Status__c from Project__c where id =: p.id];
    System.assertEquals('Billed', p.Status__c);
    }

}

Best Answer

You need to make sure you set the mock within the context. If you call Test.startTest() in between setting your mock and making the callout, it won't work.

Works

Test.startTest();
    Test.setMock(...);
    // make callout
Test.stopTest();

Error

Test.setMock(...);
Test.startTest();
    // make callout
Test.stopTest();
Related Topic