1

I am super stuck on my test coverage. I built a generic mock test class so I can reuse it. I typically just plug in the status code, status string, and body to be returned. I have used this mock class successfully multiple times. But this time, the mock class is not setting the body for some reason. I have tried re-writing my mock class in my test class, I have followed all the documentation on how to write the mock class, and have looked at other posts such as this one.

I keep getting the same result - the mock class is not setting the body. I have used this method before and have gotten the coverage I wanted so I am not sure what is different in this scenario. I would appreciate any help.

I set the body value here:

String responseObj = '{"IDScore":"931","Comply360Grade":null,"ErrorInfo":{NULL}}';

SingleRequestMockClass fakeResponse = new SingleRequestMockClass(200, 'Complete', responseObj, null);

Test.setMock(HttpCalloutMock.class, fakeResponse);

//mock data
@isTest
public class SingleRequestMockClass implements HttpCalloutMock {
    protected Integer code;
    protected String status;
    protected String bodyAsString;
    protected Blob bodyAsBlob;
    protected Map<String, String> responseHeaders;

    public SingleRequestMockClass(Integer code, String status, String body,
                                     Map<String, String> responseHeaders) {
        this.code = code;
        this.status = status;
        this.bodyAsString = body; //NOT GETTING SET
        this.bodyAsBlob = NULL;
        this.responseHeaders = responseHeaders;
    }

    public SingleRequestMockClass(Integer code, String status, Blob body,
                                     Map<String, String> responseHeaders) {
        this.code = code;
        this.status = status;
        this.bodyAsBlob = body;
        this.bodyAsString = NULL;
        this.responseHeaders = responseHeaders;
    }

    public HTTPResponse respond(HTTPRequest req) {
        HttpResponse resp = new HttpResponse();
        resp.setStatusCode(code);
        resp.setStatus(status);
        if (bodyAsBlob != null) {
            resp.setBodyAsBlob(bodyAsBlob);
        }
        else {
            resp.setBody(bodyAsString);
        }
        if (responseHeaders != null) {
             for (String key : responseHeaders.keySet()) {
            resp.setHeader(key, responseHeaders.get(key));
             }
        }
        return resp;
    }
}

Test Class

static testmethod void firstTestAccount() {
    Account a = new Account(Name = 'Test Account Olivia');
    insert a;
    Opportunity o = new Opportunity(AccountId = a.Id, Name = 'IDAnalyticsName', CloseDate = Date.today(), StageName = 'Prospecting');
    insert o;
    Contact c = new Contact(FirstName = 'FirstTest', LastName = 'LastTest', SSN_Encrypted__c = '000000000', HomePhone = '7894561333', MobilePhone = '9885556666', Email = '[email protected]', AccountId = a.Id);
    insert c;
    FPC_Address__c addr = new FPC_Address__c(Zip_Code__c = '44543', Address_1__c = 'Test Street ', City__c = 'Unity City', State__c = 'CA', Account__c = a.id, Location_Type__c = 'Home Address', Contact__c = c.Id);
    insert addr;
    Credit_Review__c cr = new Credit_Review__c(Account__c = a.Id, Opportunity__c = o.Id, PG1__c = c.Id);
    insert cr;
    Consumer_Risk_Summary__c crs = new Consumer_Risk_Summary__c(Error_Message__c = 'ID Analytics encountered an error while processing the request.', Credit_Review__c = cr.Id, Position__c = '1');
    insert crs;
    Id guarantorId1 = [SELECT PG1__c FROM Credit_Review__c WHERE Id = :cr.Id].PG1__c;
    List<Contact> serializedData = [SELECT Id, FirstName, LastName, Birthdate, SSN_Encrypted__c, SSN__c, HomePhone, MobilePhone, Email FROM Contact WHERE Id = :guarantorId1];
    List<Consumer_Risk_Summary__c> consumerRiskID = [SELECT Id FROM Consumer_Risk_Summary__c WHERE Position__c = '1' AND Id = :crs.Id];
    List<FPC_Address__c> homeAddress1 = [SELECT Address_1__c, City__c, State__c, Zip_Code__c FROM FPC_Address__c WHERE Location_Type__c = 'Home Address' AND Contact__r.Id = :guarantorId1 ORDER BY CreatedDate DESC LIMIT 1];
    IDAnalyticsEndPoint__c IDA = new IDAnalyticsEndPoint__c();
    insert IDA;
    IDA.IDAnalyticsEndpointUrl__c = 'https://test.com/thisisforprivacy';
    IDA.GetToken__c = 'https://test.com/thisisforprivacy';
    IDA.APIKEY__c = '2113465468353test';
    update IDA;
    ApexPages.currentPage().getParameters().put('Id', cr.Id);
    IDAnalyticsController ctrl = new IDAnalyticsController();
    Test.startTest();
    String responseObj = '{"IDScore":"931","Comply360Grade":null,"ErrorInfo":{NULL}}';
    String responseObj2 = '{"IDScore":"null","Comply360Grade":null,"ErrorInfo":{"The callout returned a null response."}}';
    SingleRequestMockClass fakeResponse = new SingleRequestMockClass(200, 'Complete', responseObj, null);
    SingleRequestMockClass fakeReturn500 = new SingleRequestMockClass(500, 'Error', responseObj2, null);
    Test.setMock(HttpCalloutMock.class, fakeResponse);
    Test.setMock(HttpCalloutMock.class, fakeReturn500);
    ctrl.pullIDAnalyticsReportAPEX(); //INSERTING A NEW CONSUMER_RISK_SUMMARY__C OBJECT
    ctrl.CallWebService(); //CALLING WESERVICE
    ctrl.removeCR1(); //OTHER METHODS
    ctrl.removeCRS1(); //OTHER METHODS
    Test.stopTest(); //OTHER METHODS
}

I am not using a WSDL file and would like to be able to continue to work with the template so I don't have to continue to make the mock class.

setBody not able to be set

UPDATED CODE:

static testmethod void firstTestAccount() {
    Account a = new Account(Name = 'Test Account Olivia');
    insert a;
    Opportunity o = new Opportunity(AccountId = a.Id, Name = 'IDAnalyticsName', CloseDate = Date.today(), StageName = 'Prospecting');
    insert o;
    Contact c = new Contact(FirstName = 'FirstTest', LastName = 'LastTest', SSN_Encrypted__c = '000000000', HomePhone = '7894561333', MobilePhone = '9885556666', Email = '[email protected]', AccountId = a.Id);
    insert c;
    FPC_Address__c addr = new FPC_Address__c(Zip_Code__c = '44543', Address_1__c = 'Test Street ', City__c = 'Unity City', State__c = 'CA', Account__c = a.id, Location_Type__c = 'Home Address', Contact__c = c.Id);
    insert addr;
    Credit_Review__c cr = new Credit_Review__c(Account__c = a.Id, Opportunity__c = o.Id, PG1__c = c.Id);
    insert cr;
    Consumer_Risk_Summary__c crs = new Consumer_Risk_Summary__c(Error_Message__c = 'ID Analytics encountered an error while processing the request.', Credit_Review__c = cr.Id, Position__c = '1');
    insert crs;
    crs.Bankcard_Score__c = '123';
    crs.Status__c = 'Completed';
    update crs;
    IDAnalyticsEndPoint__c IDA = new IDAnalyticsEndPoint__c();
    insert IDA;
    IDA.IDAnalyticsEndpointUrl__c = 'https://test.com';
    IDA.GetToken__c = 'https://test.com';
    IDA.APIKEY__c = '11ardgsdtestB';
    update IDA;
    ApexPages.currentPage().getParameters().put('Id', cr.Id);
    IDAnalyticsController ctrl = new IDAnalyticsController();
    String responseObj = '{"IDScore": "931", "Comply360Grade": "B", "ErrorInfo": {}}';
    SingleRequestMockClass fakeResponse = new SingleRequestMockClass(200, 'Complete', responseObj, null);
    Test.startTest();
    Test.setMock(HttpCalloutMock.class, fakeResponse);
    ctrl.CallWebService();
    Test.stopTest();
}

PICTURES OF COVERAGE: enter image description here enter image description here enter image description here

5
  • 1
    There's an exception getting thrown. What's the exception?
    – sfdcfox
    May 5, 2017 at 20:45
  • @Eric it is in the remote site setting
    – Olivia
    May 5, 2017 at 21:39
  • @Olivia watts in your catch block? is it covered. Debug the message, what does it say? Also, any chance getAccounts is called due to records being inserted before the test.startTest()? If so that could cause an error to be thrown - Test methods do not support callouts
    – Eric
    May 5, 2017 at 21:40
  • @Eric - My catch block is covered. So it recognizes that jsonStr is a null value. I will post a picture of the entire coverage.
    – Olivia
    May 5, 2017 at 21:47
  • @Olivia - Your catch block is covered because you had an error when sending the callout. Thats why the jasonStr line is uncovered. What was the error in the catch block
    – Eric
    May 5, 2017 at 21:48

3 Answers 3

5
Test.setMock(HttpCalloutMock.class, fakeResponse);
Test.setMock(HttpCalloutMock.class, fakeReturn500);

You can only set one mock per interface at a time. Your mock class has to be able to send multiple responses, if applicable.

ctrl.pullIDAnalyticsReportAPEX(); //INSERTING A NEW CONSUMER_RISK_SUMMARY__C OBJECT
ctrl.CallWebService(); //CALLING WESERVICE

You can't callout after a DML. The first thing after Test.startTest must be setMock, and the second must be your callout, with no intervening DML operations.

6
  • Interesting, I did not know this. In my code I do a DML before the webservice and after the webservice. I put the DML in it's own method and the webserice in it's own method. When I remove the DML method (pullIDAnalyticsReportAPEX) from the test class, I am getting System.ListException: List index out of bounds: 0 and when I include the DML method I get: System.NullPointerException: Attempt to de-reference a null object. (this is the jsonStr) I believe I need the DML method to run before the webservice method so that there is data for the webservice method to process. Thoughts?
    – Olivia
    May 5, 2017 at 21:01
  • oh wait...or I would split each test method up, one would test the DML and one would test the webservice. Let me try this first.
    – Olivia
    May 5, 2017 at 21:07
  • @Olivia Yeah, that might be what you need to do. Sometimes it's hard to stuff everything into one unit test.
    – sfdcfox
    May 5, 2017 at 21:13
  • when I split this into two methods I am unable to push through a method that was passing before. It serialized the data. So I don't have to post the all the code on this post, would you be open to taking this into a chat room?
    – Olivia
    May 5, 2017 at 21:41
  • @Olivia I'm sorry I missed your comment. If you'd like to chat about this, I'd be glad to help you further.
    – sfdcfox
    May 10, 2017 at 13:48
2

I think your JSON String is not valid in this line

String responseObj = '{"IDScore":"931","Comply360Grade":null,"ErrorInfo":{NULL}}';

Invalid JSON

{
    "IDScore": "931",
    "Comply360Grade": null,
    "ErrorInfo": {
        NULL
    }
}

Results in validation

Error: Parse error on line 4:
...,    "ErrorInfo": {      NULL    }}
---------------------^
Expecting 'STRING', '}', got 'undefined'

Valid JSON

{
    "IDScore": "931",
    "Comply360Grade": null,
    "ErrorInfo": {}
}
2
  • 1
    This answer would be correct, except that's not the line of code where the error's happening (this is useful info, but not related to the current error).
    – sfdcfox
    May 5, 2017 at 20:56
  • yes, you are correct May 5, 2017 at 20:58
0

This isn't my favorite solution but I ended up having to change my code to get my test class to work.

My callout method was under a return type of String. I changed this method to be a return type of HttpResponse and used the test setup in this article. So rather then using my mock template, I created a new mock class, hard coded in the values, and the class was was covered.

apex class:

public HttpResponse getAccounts() {
    HttpRequest req = new HttpRequest();
    endpoint = IDAnalyticsEndPoint__c.getInstance();
    url1 = endpoint.IDAnalyticsEndpointUrl__c;
    req.setEndpoint(url1);
    req.setMethod('POST');
    req.setBody(generateJSON());
    req.setHeader('Content-Type', 'application/json');
    req.setTimeout(120000);
    string d = getAuth();
    string e = 'token ';
    string f = e + d;
    req.setheader('Authorization', f);
    try {
        Http h = new Http();
        res = h.send(req);
        jsonStr = res.getBody();
        errorMessage();
        JSONParser parser = JSON.createParser(res.getBody());
        while (parser.nextToken() != null) {
            if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'IDScore')) {
                parser.nextToken();
                IDScore1 = parser.getText();
            }
            if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'Comply360Grade')) {
                parser.nextToken();
                Comply360Grade1 = parser.getText();
            }
            if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'ApiErrorCode')) {
                parser.nextToken();
                ApiErrorCode = parser.getText();
            }
            if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'ErrorMessage')) {
                parser.nextToken();
                ErrorMessage1 = parser.getText();
            }
        }
        return res;
    }
    catch (System.CalloutException z) {
        system.debug('z: ' + z);
        return null;
    }
}

mock class:

@isTest
global class MockHttpResponseGenerator500 implements HttpCalloutMock {
    global HTTPResponse respond(HTTPRequest req) {
        HttpResponse res = new HttpResponse();
        res.setHeader('Content-Type', 'application/json');
        res.setBody('{"IDScore":"null", "Comply360Grade":"null", "ErrorInfo":"An error has occured."}');
        res.setStatusCode(500);
        return res;
    }
}

test class:

    test.startTest();
    Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator500());
    IDAnalyticsController ctrl = new IDAnalyticsController();
    HttpResponse res = ctrl.getAccountsG3();
    String contentType = res.getHeader('Content-Type');
    System.assert(contentType == 'application/json');
    String actualValue = res.getBody();
    String expectedValue = '{"IDScore":"null", "Comply360Grade":"null", "ErrorInfo":"An error has occured."}';
    System.assertEquals(actualValue, expectedValue);
    System.assertEquals(500, res.getStatusCode());
    test.stopTest();

You must log in to answer this question.

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