0

I try to use HttpCalloutMock to test my post callout. But I become System.NullPointerException: Attempt to de-reference a null object. I need to test and web token, and posted object. I'm just learning and don't understand how actually use a Mock in this situation. Callout:

    public class Token{
public String accessToken{get;set;}    
}

public static String accessTokenBody(){  //our web token (data is in fields)
        Settings__c settings = [SELECT ConsumerKey__c, ClientSecret__c, Username__c, Password__c, SecurityToken__c
                                FROM Settings__c
                                WHERE Name = 'OurSettings'];  
        String consumerKey = settings.ConsumerKey__c;
        String consumerSecret = settings.ClientSecret__c;
        String username = settings.Username__c;
        String password = settings.Password__c + settings.SecurityToken__c;
        String request = 'grant_type=password&client_id=' + consumerKey +'&client_secret=' + consumerSecret +
                         '&username=' + username + '&password='+password;
        return request;
    }

public static String GenerateJSON(Type__c t){
//I will send and post it like a record in another org:
    Map<String, String> fieldMap = new Map<String, String>{
                   'Name' => t.Name,
                   'Desc__c' => t.Type_Description__c};    
    String serialized = JSON.serialize(fieldMap);         
    return serialized;
 }

public static HttpRequest httpRequest(String service){
    String requestBody = accessTokenBody();
    HttpRequest ourRequest = new HttpRequest();
    ourRequest.setBody(requestBody);
    ourRequest.setMethod(service);
    ourRequest.setEndpoint('https://p21.lightning.force.com/services/oauth2/token');
    return ourRequest;
}

public static HttpRequest finalHttpRequest(String token, String method, String endpointUrl){
    HttpRequest finalRequest = new HttpRequest();
    finalRequest.setHeader('Authorization','Bearer ' + token);
    finalRequest.setHeader('Content-Type','application/json');
    finalRequest.setHeader('accept','application/json');
    finalRequest.setMethod(method);
    finalRequest.setEndpoint('https://p21.lightning.force.com/services/oauth2/token' + endpointUrl);
    return finalRequest;
}

public static HttpResponse postCallout(String positionId) {
    Http ourHttp = new Http();
    HttpRequest request = httpRequest('POST');
    HttpResponse response = ourHttp.send(request);      
    Token objAuthenticationInfo = (Token)JSON.deserialize(response.getbody(), Token.class);

    if(objAuthenticationInfo.ACCESS_TOKEN != null){
        Type__c typ = [SELECT Id, Name FROM Type__c WHERE Id =: TypeID];
        HttpRequest finalRequest = finalHttpRequest(objAuthenticationInfo.ACCESS_TOKEN, 'POST', '');
        finalRequest.setBody(GenerateJSON(typ));
        HttpResponse finalResponse = ourHttp.send(finalRequest);
        if(finalResponse.getStatusCode() == 200) {
            System.debug('CREATED:  ' + finalResponse.getBody());
            return finalResponse;
        }else {
            return null;
        }
    }
    return null;
}

Mock:

@isTest
global class AnimalsHttpCalloutMock implements HttpCalloutMock {
global HTTPResponse respond(HTTPRequest request) {
    HttpResponse response = new HttpResponse();
    response.setHeader('Content-Type', 'application/json');
    Settings__c settings = [SELECT ConsumerKey__c, ClientSecret__c, Username__c, 
                        Password__c, SecurityToken__c
                        FROM Settings__c
                        WHERE Name = 'OurSettings'];
        String serialized = JSON.serialize(settings);
        response.setBody(serialized);
        response.setStatusCode(200);
        return response;
}
}

Test:

@isTest
private class CalloutTest {


@isTest
static void testPostCallout() {              
    Settings__c settings = new Settings__c(Name = 'OurSettings',
                                           ConsumerKey__c = '****',
                                           ClientSecret__c = '*****',
                                           Username__c = '*****',
                                           SecurityToken__c = '****',
                                           Password__c = 'mypassword1');
    insert settings;

    String consumerKey = settings.ConsumerKey__c;
    String consumerSecret = settings.ClientSecret__c;
    String username = settings.Username__c;
    String password = settings.Password__c + settings.SecurityToken__c;
    String request = 'grant_type=password&client_id=' + consumerKey +'&client_secret=' + consumerSecret +
                     '&username=' + username + '&password='+password;

    Type__c typ = new Type__c(Name = 'ttt');
    insert typ;

    Http ourHttp = new Http();
    String requestBody = CalloutJobAdvertisement.accessTokenBody();
    System.debug('request: ' + request);
    System.debug('request2: ' + requestBody);
    HttpRequest ourRequest = new HttpRequest();
    ourRequest.setBody(requestBody);
    ourRequest.setMethod('POST');
    ourRequest.setEndpoint('https://p21.salesforce.com/services/oauth2/token');    
    Test.startTest(); 
    Test.setMock(HttpCalloutMock.class, new AnimalsHttpCalloutMock());
    HttpResponse response = CalloutJobAdvertisement.postCallout(pos.Id);

//Error is here. System.NullPointerException: Attempt to de-reference a null object

    String contentType = response.getHeader('Content-Type');
    System.assert(contentType == 'application/json');
    String actualValue = response.getBody();
    System.debug(response.getBody());
    String expectedValue = '{"Name":"ttt"}';
    System.assertEquals(actualValue, expectedValue);
    System.assertEquals(200, response.getStatusCode());
    Test.stopTest(); 
}

public class OAuth2{
    public String ACCESS_TOKEN{get;set;}    
}
}

Coverage is just on my getAccess(), httpRequest() and 5 first rows of postCallout() + last row return null;

4

Your problem is that you're not returning an object with an access_token value. What you really need is two separate responses. In other words, your mock class has to determine which response to send back:

@isTest
global class AnimalsHttpCalloutMock implements HttpCalloutMock {
global HTTPResponse respond(HTTPRequest request) {
    HttpResponse response = new HttpResponse();
    response.setHeader('Content-Type', 'application/json');
    String serialized;
    if(request.getEndpoint().contains('services/oauth2/token')) {
      serialized = '{ "access_token": "FAKE-ACCESS-TOKEN" }';
    } else {
      serialized = '{ }'; // return correct JSON for second callout here
    }
    response.setBody(serialized);
    response.setStatusCode(200);
    return response;
}
}

P.S. To get 100% coverage, you're going to have modify the above mock to be intelligent to determine if it should return a token or not (because you need to be able to take the access_token equals null path in your if-else statement).

  • I noticed that with your code I even don't need in my test part before Test.startTest(). And GET method work with the same test great (I mean coverage and asserts are good): I just change method to the HttpResponse response = CalloutJobAdvertisement.getCalloutResponseContents();. Is it right? I mean, it looks too easy - same tests for different methods. – user60684 Oct 15 '18 at 16:57
  • 1
    @user60684 Testing really can be that easy most of the time. Just make sure you have proper assertions to verify logic, and you'll be fine. – sfdcfox Oct 15 '18 at 17:51

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.