Tuesday, March 28, 2017

Different ways of testing HTTP callout in apex

As we all know that test methods do not support HTTP callout, so all test method performing callout will fail.


In order to avoid the test class failure, we mainly use Test.IsRunningTest method in apex class. By using this method, we make sure that particular block of code performing HTTP callout should not run when called by test class methods.

if(!Test.isRunningTest()){
// apex code for HTTP callout
}
but this approach will reduce your code coverage. As per salesforce, you need to have atleast 75% coverage for all your apex code.

We will now go through different options through which we can test HTTP callout and increase our code coverage.

  • Using static resource
You can store the response of your HTTP callout in text file and upload it static resource. Now you can use built in apex class StaticResourceCalloutMock or MultiStaticResourceCalloutMock to build mock response and get response from static resource.

First create an instance of StaticResourceCalloutMock:

StaticResourceCalloutMock mockCallout = new StaticResourceCalloutMock();
mockCallout.setStaticResource('StaticResourceForCallout');
mockCallout.setStatusCode(200);
mockCallout.setHeader('Content-Type', 'application/json');

Now set mock callout mode in test method by using below method:

Test.setMock(HttpCalloutMock.class, mockCallout );

After this call method which perform callout. As we have set mock test callout, apex will not perform callout and will return response from static resource.

Note: MultiStaticResourceCalloutMock helps you test different HTTP callout with different endpoint URL. you can create instance of this class and specify callout response in different static resource for different endpoints and then set this as mock callout in test method.

  • Generating mock response in test by implementing the HttpCalloutMock Interface 
Create a apex class which implements HttpCalloutMock interface. In this interface, you can specify response which will be returned if test method perform callout.

@isTest
global class HTTPMockCallout implements HttpCalloutMock {
    global HTTPResponse respond(HTTPRequest req) {
        // specify the response here
        // return response.
    }

Note:
       1. Class should be public or global which implements HttpCalloutMock
       2. You can use @IsTest on this class as this will be used only through test class. In this way it                   will not count against organization code size limit.

Now you can set mock response in test method before calling method which perform HTTP callout.

Test.setMock(HttpCalloutMock.class, new HTTPMockCallout());

Below is sample code to provide code coverage to "CalloutUtility" apex class using both approaches mentioned above


Hope this will help!!!!


More Blogs>>: 
DYNAMIC APEX IN SALESFORCE
FETCHING FILE FROM EXTERNAL/PUBLIC URL AND STORING IT IN SALESFORCE
SOQL INJECTION IN SOQL
CUSTOM METADATA AND CUSTOM SETTINGS IMPLEMENTATION TRICKS
SMART TABLE USING ANGULARJS IN VISUALFORCE PAGE
VISUALFORCE COMPONENT FOR RECORD STATUS BAR

2 comments:

  1. Any help for testing this code?
    *************************8
    global with sharing class NavikUtilityClass {
    global Static HttpResponse callSendToNavikAuthentication(String endURL,String methodType,String methodFunctional,String accNum, String contact, String recommendation,Integer dataId,List input,List dataIds) {
    String baseUrl = EndPoint__c.getvalues('BaseURL').EndPointURL__c;
    navikAuthDomain.response mapResp = navikAuthentication.getMapId(UserInfo.getUserEmail());
    Http http = new Http();
    HttpRequest request = new HttpRequest();
    request.setHeader('sessionToken',mapResp.sessionToken);
    request.setMethod(methodType);
    if(methodFunctional == 'ACTIVITY'){
    request.setEndpoint(baseUrl + '/' + endURL);
    }
    if(methodFunctional == 'DRILLDOWN'){
    request.setEndpoint(baseUrl + '/' + endURL);
    String accNo = EncodingUtil.urlEncode(accNum,'UTF-8');
    String cont = EncodingUtil.urlEncode(contact,'UTF-8');
    String recom = EncodingUtil.urlEncode(recommendation,'UTF-8');
    request.setBody('accountNumber='+accNo+'&contact='+cont+'&recommendation='+recom);
    }
    if(methodFunctional == 'SPECIFICRECOMM'){
    request.setHeader('content-type', 'application/json');
    request.setHeader('Accept', 'application/json');
    request.setEndpoint(baseUrl + '/' + endURL);
    request.setEndpoint(baseUrl + '/'+endURL+dataId);
    }
    if(methodFunctional == 'SENDEMAIL'){
    request.setHeader('content-type', 'application/json');
    request.setHeader('Accept', 'application/json');
    request.setEndpoint(baseUrl + '/' + endURL);
    String s = JSON.serialize(input);
    request.setBody(s);
    }
    if(methodFunctional == 'INVALID'){
    request.setHeader('content-type', 'application/json');
    request.setHeader('Accept', 'application/json');
    request.setEndpoint(baseUrl + '/' + endURL);
    request.setBody(JSON.serializePretty(dataIds));
    }
    HttpResponse response = null;
    try {
    response = http.send(request);
    } catch(System.CalloutException e) {
    System.debug('Callout error: '+ e);
    System.debug(response.toString());
    }
    return response;
    }
    }

    ReplyDelete