0

I have Mock callouts in my test class but the test class didn't cover some of the codes. It has been solved before but there were changes to my code and now my test class isn't working. The scenario this time is different. My Post & Get Callouts will be handled by one method. My first callout is for me to get an access token. The second callout will be using the access token.

global class Overview {
@future(callout=true)
global static void main(){
    Org_Info__c orgLogins = Org_Info__c.getOrgDefaults();
    String end_point = (orgLogins.Sandbox__c == true) ? 'https://test.saleforce.com' : 'https://login.salesforce.com';
    end_point       += '/services/oauth2/token';
    String client_id = orgLogins.Client_ID__c;
    String client_secret = orgLogins.Client_Secret__c;
    String username = orgLogins.Username__c;
    String password = orgLogins.Password__c;
    String payload = 'grant_type=password' + '&username=' + username + '&password=' + password + '&client_id=' + client_id + '&client_secret=' + client_secret;
    HttpResponse response = makeCallout(end_point, 'POST', 'Content-Type', 'application/x-www-form-urlencoded', payload);
    if(response.getStatusCode() == 200){
        String body = response.getBody();
        Map<String, Object> mapResponse = (Map<String, Object>)JSON.deserializeUntyped(body); 
        String accessToken = string.valueOf(mapResponse.get('access_token'));
        String endP = Url.getSalesforceBaseUrl().toExternalForm() + '/services/data/v43.0/limits/';
        response = makeCallout(endP, 'GET', 'Authorization', 'OAuth ' + accessToken, '');
        if(response.getStatusCode() == 200) insertOv(response);
    }
}
global static HttpResponse makeCallout(String endPoint, String method, String headerKey, String headerValue, String payload){
    HttpRequest req = new HttpRequest();
    req.setEndpoint(endPoint);
    req.setMethod(method);
    req.setHeader(headerKey, headerValue);
    if(req.getEndpoint().endsWith('token')) req.setBody(payload); 
    Http http = new Http(); 
    HttpResponse res = http.send(req); 
    return res;   
}
global static void insertOv(HttpResponse rawResp){
    Map<String, Object> SysOvMap = (Map<String,Object>)JSON.deserializeUntyped(rawResp.getBody()); // deserializing result the services/data/v43.0/limits request
    Map<String, Object> dataStorage = (Map<String,Object>)SysOvMap.get('DataStorageMB'); 
    Map<String, Object> apiUsage = (Map<String,Object>)SysOvMap.get('DailyApiRequests');
    System_Overview__c sysOv = new System_Overview__c();
    sysOv.Total_Storage__c = Integer.valueof(dataStorage.get('Max'));
    sysOv.Remaining_Storage__c = Integer.valueof(dataStorage.get('Remaining'));
    sysOv.Used_Storage__c = sysOv.Total_Storage__c - sysOv.Remaining_Storage__c;
    sysOv.Max_API__c = Integer.valueof(apiUsage.get('Max'));
    sysOv.Usable_API__c = Integer.valueof(apiUsage.get('Remaining'));
    sysOv.Requested_API__c = sysOv.Max_API__c - sysOv.Usable_API__c;
    sysOv.Retrieve_DateTime__c = Datetime.now();
    insert sysOv; // insert System Overview details
}}

Here's my test class

@isTest
global class Test_Overview {
@isTest static void testCallout() {

    System.test.setMock(HttpCalloutMock.class, new Test_OverviewMockCallout());
    HttpResponse res = Overview.makeCallout('https://login.salesforce.com/services/oauth2/token', 'POST', 'Content-Type', 'application/x-www-form-urlencoded', 'some credentials');
    res.setStatusCode(200);

    HttpResponse res2 = Overview.makeCallout(Url.getSalesforceBaseUrl().toExternalForm() + '/services/data/v43.0/limits/', 'GET', 'Authorization', 'OAuth the access token here', '');
    res2.setStatusCode(200);
    }
}

Here's my mock callout:

@isTest
global class Test_OverviewMockCallout implements HttpCalloutMock{

global HTTPResponse respond(HTTPRequest req) {
    HttpResponse res = new HttpResponse();
    if(req.getEndpoint().endsWith('token')){
        System.assertEquals('https://login.salesforce.com/services/oauth2/token', req.getEndpoint());
        System.assertEquals('POST', req.getMethod());
        res.setHeader('Content-Type', 'application/x-www-form-urlencoded'); 
        res.setBody('{"access_token": "access token here",' +
                '"instance_url": "https://ap4.salesforce.com","id": "https://login.salesforce.com/id/0046878SDSFER7892KDSDS/09823j8as4dffh73hjha23asdf",' +
                '"token_type": "Bearer","issued_at": "9102837029332847","signature": "EAMz1IUncdkYWglusKsQkliasudevM7A+rLRpxUhsYcKaY="}');
        res.setStatusCode(200);            
    }
    else if(req.getEndpoint().endsWith('limits/')){
        String endP = Url.getSalesforceBaseUrl().toExternalForm() + '/services/data/v43.0/limits/';
        System.assertEquals(endP, req.getEndpoint());
        System.assertEquals('GET', req.getMethod());
        res.setHeader('Authorization','OAuth ' + 'access token here');
        res.setBody('sample response here');
        res.setStatusCode(200); 
    }
    return res;
}
}

Now the problem is... my test class only covers the method with the callout - makeCallout(). The methods main() and insertOv() isn't covered.

8
  • What have you done so far? Have you thought about using httpcalloutmock? developer.salesforce.com/docs/atlas.en-us.apexcode.meta/…
    – Ranga
    Aug 22, 2018 at 5:53
  • @Ranga yes. my test already covers my callout. I'm just having trouble how to make my test class cover that area where there is deserialization.
    – cookie
    Aug 22, 2018 at 5:57
  • 1
    Ok. When you set the response body in the mock, create the same structure you are expecting (map<string,object>) and then serialise it and set it as the body. It would help if you post your current test method if you need more specifics
    – Ranga
    Aug 22, 2018 at 6:06
  • @Ranga I have updated my question with my current test class
    – cookie
    Aug 23, 2018 at 1:39
  • This is a great example of a custom echohttpmock class that may help salesforce.stackexchange.com/questions/228369/…
    – Eric
    Aug 23, 2018 at 6:00

2 Answers 2

2

For writing the Test class for Callout. One approach is to use StaticResourceCalloutMock

So first create a static resource with name like "jsonTestMockup.json".

After that you can set you mockup for test method like:

StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
mock.setStaticResource('jsonTestMockup.json');
mock.setStatusCode(200); // Or other appropriate HTTP status code
mock.setHeader('Content-Type', 'application/json'); // Or other appropriate MIME type like application/xml

//Set the mock callout mode
Test.setMock(HttpCalloutMock.class, mock);

and then start the test using Test.startTest(); after that execute the callout code

2
  • 1
    Can you modify this to say "One approach is" rather than "You should use"? Depending on the code being tested, implementing your own HttpCalloutMock could be a better approach.
    – Keith C
    Aug 22, 2018 at 7:52
  • @KeithC Thanks for suggestion :) Aug 22, 2018 at 7:56
1

I was able to pull it off. My main test class is calling 2 different Mock callouts in two separate class has caused the problem. I only need 1 class with mock callout and create conditional statement to perform the mock callout that corresponds the request.

2
  • I hope you went the rout I posted or your mock is going to get filled with conditionals as you write more tests
    – Eric
    Aug 27, 2018 at 4:26
  • Hi @Eric , I went to check your EchoHttpMock Class. Do I only need that test class or do I still have to create another test class containing the method that the test calls?
    – cookie
    Aug 31, 2018 at 5:53

You must log in to answer this question.

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