-1

I become an error System.NullPointerException: Attempt to de-reference a null object in my test:

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');
    //Error is here: 
    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');
    response.setBody('{"Name":"ttt"}');
    response.setStatusCode(200);
    return response; 
}

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

    @isTest
    private class CalloutTest {

    @isTest
    static void testPostCallout() {      

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

        Settings__c settings = new Settings__c(Name = 'OurSettings',
                                               ConsumerKey__c = 'REMOVED',
                                           ClientSecret__c = 'REMOVED',
                                           Username__c = 'mail@mail.com',
                                           SecurityToken__c = 'REMOVED',
                                           Password__c = 'REMOVED');
    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;

    Http ourHttp = new Http();
    String requestBody = CalloutClass.accessTokenBody();
    System.debug('request: ' + request);
    System.debug('request2: ' + requestBody);
    HttpRequest ourRequest = new HttpRequest();
    ourRequest.setBody(request);
    ourRequest.setMethod('POST');
    ourRequest.setEndpoint('https://p21.salesforce.com/services/oauth2/token');
    Type__c typ = new Type__c(Name = 'ttt');
    insert typ;

    Test.startTest(); 
    Test.setMock(HttpCalloutMock.class, new AnimalsHttpCalloutMock());
    HttpResponse response = CalloutClass.postCallout(typ.Id);
    //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();
    }    
    }
  • 2
    You should consider changing all the sensitive, security-related values I just edited out of your question. – David Reed Oct 13 '18 at 22:46
  • 1
    On which line is the NullPointerException thrown? What have you done to try to fix it? This exception is almost always fixable just by tracing the null value through your data. – David Reed Oct 13 '18 at 22:47
  • Thank you) But token data was fake) All is ok. – user60684 Oct 14 '18 at 9:48
1

This is pretty straightforward. Your code is designed to return a null value given an invalid response, and that's exactly what it's doing.

Your test does this:

Test.setMock(HttpCalloutMock.class, new AnimalsHttpCalloutMock());
HttpResponse response = CalloutClass.postCallout(typ.Id);
//System.NullPointerException: Attempt to de-reference a null object: 
String contentType = response.getHeader('Content-Type');

Your mock returns this value when called:

response.setBody('{"Name":"ttt"}');

And then your postCallout() method does this with the mock return value:

Token objAuthenticationInfo = (Token)JSON.deserialize(response.getbody(), Token.class);

if(objAuthenticationInfo.ACCESS_TOKEN != null){
    <snipped>
}
return null;

postCallout() is designed to return null if it doesn't get a valid Token structure back. You supplied a mock that does not return a valid Token JSON body, so postCallout() returns null - as designed.

Your test then tries to dereference that null value, throwing an exception.

You need to write a mock class designed for your API. You can't just drop a Trailhead mock class in - as you've seen, it won't work. One approach - not the only approach - is to actually construct a Token object in your mock and return as the response body the string resulting from doing JSON.serialize() on that object.

  • So I need to put in response.setBody our request with token data, right? And just then add to mock (or create another Mock) our obkect's data? – user60684 Oct 14 '18 at 9:51
  • Your Mock needs to return a value that is representative of the real API's return value so that your code can successfully execute. – David Reed Oct 14 '18 at 11:18
  • Okey. But when I try to put in response.setBody() my token string or JSON.serialize(my token string) it write System.JSONException: Unexpected character ('}' (code 125)): was expecting a colon to separate field name and value at [line:1, column:231] or System.JSONException: Malformed JSON: Expected '{' at the beginning of object :( How can it "eat" my token? – user60684 Oct 14 '18 at 12:56
  • 1
    Your mock has to return the JSON representation of a Token object, not the token string itself. Its return value has to be able to be deserialized as a Token object. – David Reed Oct 14 '18 at 12:56
  • Okay. I call in Mock my Token object. Then I make String serialized = JSON.serialize(settings); response.setBody(serialized); And get the same error System.NullPointerException: Attempt to de-reference a null object in the same place. Sorry, I'm just learning) – user60684 Oct 14 '18 at 17:34

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.