[SalesForce] Need help with Test Class for HTTP Callout

I have an extension to a vf page which makes an http call to a web service. I am tying to follow the salesforce guide for setting up the HttpCalloutMock Interface, though I don't quite get how to set it up for my specific case. Some specific questions I have:

  • Does the MockHttpResponse and test class need to mirror what I have in my extension method? I mean, do I need to include Blob, API keys, etc?
  • How should I set the HTTP response in my test class, as it is I get the error "Method does not exist or incorrect signature". I also try to set it as String res = ClinicalStudySetupExtension.callRestEndPoint();, but that doesn't change anything either.

My extension

public with sharing class ClinicalStudySetupExtension {

private String studyJson;
private String result;
private String protocolNumber;
public String query {get; set;}
public Boolean searched {get; set;}
public Clinical_Study__c cStudy {get; set;}
private ApexPages.StandardController std {get; set;}

//controller
public ClinicalStudySetupExtension(ApexPages.StandardController std) {

    this.std = std;
    this.studyJson = callRestEndPoint();

    query = '';
    searched=false;
    String queryStr=ApexPages.currentPage().getParameters().get('query');
    if (queryStr!=null)
    {
        protocolNumber=queryStr;
        runSearch();
    }
}

public pageReference runSearch() {//runSearch takes the input 'query' and passes it to the REST api call

    searched=true;
    String searchStr = ''+query+'';
    system.debug('Study name: ' + query);
    protocolNumber = searchStr.deleteWhitespace();

    this.studyJson = callRestEndPoint();

    return null;
  }

private string callRestEndPoint() {//the rest api call generates a json string and passes it to the json parser      
    Http h = new Http();
    HttpRequest req = new HttpRequest();
    HttpResponse res = new HttpResponse();

    String username = 'ex';
    String password = 'ex';

    Blob headerValue = Blob.valueOf(username + ':' + password);
    String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue);
    req.setClientCertificateName('CN');
    req.setHeader('Authorization', authorizationHeader);
    req.setHeader('Api-Key', '777..');
    req.setTimeout(120000);

    req.setMethod('GET');
    req.setEndpoint('https://example.com/study/'+protocolNumber);      

    String result = '';
    try{
        res = h.send(req);
        result = res.getBody();
        }
    catch(System.CalloutException e){
        result = res.toString();
        }

    return result;     
}

My test class

public static testMethod void testCallout() {
    // Set mock callout class 
    Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator());

    // Call method to test.
    // This causes a fake response to be sent
    // from the class that implements HttpCalloutMock. 
    HttpResponse res = ClinicalStudySetupExtension.callRestEndPoint();

    // Verify response received contains fake values
    String contentType = res.getHeader('Content-Type');
    System.assert(contentType == 'application/json');
    String actualValue = res.getBody();
    String expectedValue = '{"study":{"moleculeDescription":"RONTALIZUMAB","protocolTitle":"IMM","protocolNumber":"GA00806","studyName":"Interferon alpha in SLE Phase II LCM Option","therapeuticArea":"INFLAMMATORY,AUTOIMMUNE&BONE","startDate":"2009-03-25","endDate":"2013-08-22"}}';
    System.assertEquals(actualValue, expectedValue);
    System.assertEquals(200, res.getStatusCode());
}

The MockHttpResponseGenerator

@isTest

global class MockHttpResponseGenerator implements HttpCalloutMock {
    // Implement this interface method
    global HTTPResponse respond(HTTPRequest req) {
        // Optionally, only send a mock response for a specific endpoint
        // and method.
        System.assertEquals('https://example.com/study/GA00806', req.getEndpoint());
        System.assertEquals('GET', req.getMethod());

        // Create a fake response
        HttpResponse res = new HttpResponse();
        res.setHeader('Content-Type', 'application/json');
        res.setBody('{"study":{"moleculeDescription":"RONTALIZUMAB","protocolTitle":"IMM","protocolNumber":"GA00806","studyName":"Interferon alpha in SLE Phase II LCM Option","therapeuticArea":"INFLAMMATORY,AUTOIMMUNE&BONE","startDate":"2009-03-25","endDate":"2013-08-22"}}');
        res.setStatusCode(200);
        return res;
    }
}

Best Answer

The MOCKHTTP class ss returning EXACTLY what the regular Endpoint would return.

Since your class ClinicalStudySetupExtension.callRestEndPoint() is PRIVATE Method of ClinicalStudySetupExtension you simply need to instantiate your controller as it will call the method which in turn will make the callout thus getting a response based on the HTTPMOCK class and process based on the controller

ClinicalStudySetupExtension con = New ClinicalStudySetupExtension(New ApexPages.StandardController(YOUROBJECT));

The point of the HTTPMOCK is to return an HTTPResponse just like an endpoint would.

Also, no need for a system assert in your HTTP Mock Class. You are going to construct and return different responses based on the request parameters sent to endpoint by whatever class / method calls it. You can use the same HTTPMOCK class for several methods from a related class that may use PUT, GET, POST, etc or different endpoints and wrap them all up in one HTPMOCK class to generate the appropriate response.

Once you instantiate the controller assert the value of 'this.studyJson' for the value of {"study":{"moleculeDescription":"RONTALIZUMAB","protocolTitle":"IMM","protocolNumber":"GA00806","studyName":"Interferon alpha in SLE Phase II LCM Option","therapeuticArea":"INFLAMMATORY,AUTOIMMUNE&BONE","startDate":"2009-03-25","endDate":"2013-08-22"}} since this is what your controller sets based on the response.

Clear as mud?

Related Topic