0

I am doing do a callout trough a processbuilder with a future call. Before I do the call I get some variables from a custom setting. When I do an insert in my testclass for my custom setting I get the error System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out. How do I advoid this?

See my class:

 public class or_service {
    @InvocableMethod
    public static void InvocePutProperty(List<String> pNames) {
         for (String pName : pNames) {
             PutProperty(pName);
         }
    }

    public static void PutProperty(String pName) {

        List<Orbirental_Service__c> os = null;

        Http http = new Http();
        HttpRequest request = new HttpRequest();

        try {
            os = [SELECT Url__c, ApiKey__c FROM Orbirental_Service__c LIMIT 1]; 
        }catch(QueryException ex) {
            os = null;
        }

        request.setEndpoint(os[0].Url__c +'v1/properties');
        request.setMethod('POST');
        request.setHeader('Content-Type', 'application/json');
        request.setHeader('X-ORBIRENTAL-APIKEY', os[0].ApiKey__c);
        // Set the body as a JSON object
        request.setBody('{"type": "HOUSE",'+
                        '"name":'+ pName +
                        ',"agencyUid": "0000000-000-000-00-000",'+
                        '"baseGuests": 4,'+
                        '"maximumGuests": 6,'+
                        '"baseDailyRate": 220,'+
                        '"city": "Utrecht",'+
                        '"state": "Utrecht",'+
                        '"acceptInstantBook": false,'+
                        '"isActive": true}');
        HttpResponse response = http.send(request);
        // Parse the JSON response
        if (response.getStatusCode() != 200) {
            System.debug('The status code returned was not expected: ' +
                         response.getStatusCode() + ' ' + response.getStatus());
        } else {
            System.debug(response.getBody());
        }
        //return response;     
    }

}

Test

    @isTest
private class or_serviceTest {
   @isTest static  void testGetAgencies() {

        Orbirental_Service__c  setting = new Orbirental_Service__c(ApiKey__c = 'abcdefgh',Url__c = 'http://api.sandbox.orbirental.com/');
        insert setting;

        // Create the mock response based on a static resource
        StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
        mock.setStaticResource('GetAgenciesResource');
        mock.setStatusCode(200);
        mock.setHeader('Content-Type', 'application/json;charset=UTF-8');
        Test.setMock(HttpCalloutMock.class, mock);
        HttpResponse result = or_service.GetAgencies();
        System.assertNotEquals(null,result,
            'The callout returned a null response.');
        System.assertEquals(200,result.getStatusCode(),
          'The status code is not 200.');
        System.assertEquals('application/json;charset=UTF-8',
          result.getHeader('Content-Type'),
          'The content type value is not expected.');  
        List<Object> results = (List<Object>) 
            JSON.deserializeUntyped(result.getBody());
        List<Object> agency = (List<Object>) results.get('agency');
       System.assertEquals(1, agency.size(),
        'The array should only contain 1 item.');          
    }   
}

1 Answer 1

2

You have two options:

Option one: Use a @TestSetup method to insert the setting before your test method i.e.

@TestSetup static void setup() {
    Orbirental_Service__c  setting = new Orbirental_Service__c(ApiKey__c = 'abcdefgh',Url__c = 'http://api.sandbox.orbirental.com/');

    insert setting;    
}
@isTest static  void testGetAgencies() {
    // Create the mock response based on a static resource
    StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
    // etc.
}

Option two, use Test.startTest() and Test.stopTest() to separate the setup code from the actual part where you do the testing i.e.

    @isTest
private class or_serviceTest {
   @isTest static  void testGetAgencies() {

        Orbirental_Service__c  setting = new Orbirental_Service__c(ApiKey__c = 'abcdefgh',Url__c = 'http://api.sandbox.orbirental.com/');
        insert setting;

        // Create the mock response based on a static resource
        StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
        mock.setStaticResource('GetAgenciesResource');
        mock.setStatusCode(200);
        mock.setHeader('Content-Type', 'application/json;charset=UTF-8');
        Test.setMock(HttpCalloutMock.class, mock);
        // ************************* Note the change here!
        Test.startTest();
        HttpResponse result = or_service.GetAgencies();
        Test.stopTest();

        System.assertNotEquals(null,result,
            'The callout returned a null response.');
        System.assertEquals(200,result.getStatusCode(),
          'The status code is not 200.');
        System.assertEquals('application/json;charset=UTF-8',
          result.getHeader('Content-Type'),
          'The content type value is not expected.');  
        List<Object> results = (List<Object>) 
            JSON.deserializeUntyped(result.getBody());
        List<Object> agency = (List<Object>) results.get('agency');
       System.assertEquals(1, agency.size(),
        'The array should only contain 1 item.');          
    }   
}

Which is best? Using @TestSetup is good for when you don't need a reference to the data you're inserting in your actual test method, or you don't mind querying it back, and every test in the class is OK to run with those records in existence. It's more efficient if you have lots of tests in the class, so your tests may run faster.

Using Test.startTest() and Test.stopTest() is good practice anyway, because it creates a new set of governor limits for the test and it makes sure any batch, future, and queueable code gets run.

2
  • Thanks for your help. Any Idea why I get: NullPointerException: Static Resource not found: GetAgenciesResource
    – Thomas
    Commented Oct 9, 2018 at 9:34
  • Sounds like your static resource might have a slightly different name to what you have in your code? Or maybe you just haven't uploaded it yet?
    – Aidan
    Commented Oct 9, 2018 at 10:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .