0

I am attempting to write a series of unit tests on a 2300+ line APEX class. The gist of the class is that it makes a Rest Request and retrieves an XML object from a web service. The class then assigns nodes from the XML file to objects in the Account, Opportunity and other object tables.

At this time, we have 0% code coverage. What should be tested, what should not be tested (such as the web service call), and how can we assure satisfactory code coverage for this type of class?

After seeing this question put on hold as too broad, and working a bit with REST request and HTTP Callout mocks, I've come up with the following:

public with sharing class CalloutClass {
public static HttpResponse getInfoFromExternalService(){
    RestRequest req = new RestRequest(); 
    req.requestURI = URL.getSalesforceBaseUrl().toExternalForm() + '/services/apexrest/IFXLoadXML/TEST';
    req.setMethod ('POST');
    Http h = new Http();
    RestResponse res = h.send(req);
    return res;
}

}

The test now has an error stating that HttpRequest doesn't have requestURI. So, I need to essentially make this mock a Rest request instead of an HttpRequest. Is that correct? If so, please help with any example code available to accomplish this callout mock within a test class. Thanks, and apologies for the broad initial question.

5

Your logic should be tested completely... for webservice calls there are mock callouts you can make to test out your logic. Salesforce HttpCalloutMock Doc

Pretty much your mock method will have your preloaded response since test cases cannot make callouts, this way your apex logic can run as though it is making a callout.

Your http mock callout will look like such.

global class YourHttpCalloutMockImpl implements HttpCalloutMock {
    global HTTPResponse respond(HTTPRequest req) {
        // Create a fake response.
        // Set response values, and 
        // return response.
    }
}

and your test classes will know what callout to use by providing it with the class

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

Working example provided by salesforce within the doc is as follows:

HTTP CALLOUT MOCK

@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('http://api.salesforce.com/foo/bar', req.getEndpoint());
        System.assertEquals('GET', req.getMethod());

        // Create a fake response
        HttpResponse res = new HttpResponse();
        res.setHeader('Content-Type', 'application/json');
        res.setBody('{"foo":"bar"}');
        res.setStatusCode(200);
        return res;
    }
}

ORIGINAL CALLOUT METHOD

public class CalloutClass {
    public static HttpResponse getInfoFromExternalService() {
        HttpRequest req = new HttpRequest();
        req.setEndpoint('http://api.salesforce.com/foo/bar');
        req.setMethod('GET');
        Http h = new Http();
        HttpResponse res = h.send(req);
        return res;
    }
}

TEST CASE

@isTest                        
private class CalloutClassTest {
     @isTest static 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 = CalloutClass.getInfoFromExternalService();

        // Verify response received contains fake values
        String contentType = res.getHeader('Content-Type');
        System.assert(contentType == 'application/json');
        String actualValue = res.getBody();
        String expectedValue = '{"foo":"bar"}';
        System.assertEquals(actualValue, expectedValue);
        System.assertEquals(200, res.getStatusCode());
    }
}
| improve this answer | |
3

In addition to Double A's response, I find it useful to place mock responses within StaticResources and then have my mock class read the StaticResource and return the XML (or JSON) payload into a string, ready for parsing/deserialization.

This is particularly handy when it is easier to use JSON or XML tools to construct the data than to build lots of code or construct elaborate Apex strings to simulate the mock response. Or, you might have many live examples of valid responses that you've already collected and want to adapt for use as mock responses.

Here's an example Mock inner class I used in a testmethod that did a REST SOQL call to a remote SFDC org. In your use case, the StaticResource would contain XML

//  ----------------------------------------------------------------
//  MOCK Callout classes
//  ----------------------------------------------------------------
public class MockRemoteSfdcOrgSoqlResponseGenerator implements HttpCalloutMock {
    private Boolean enableMockSuccess;
    private String  testDataset;

    public HTTPResponse respond(HTTPRequest req) {
    // Create a fake response
        HttpResponse res = new HttpResponse();
        res.setBody([select id, body, name from StaticResource where name = :this.testDataset][0].body.toString());     
        res.setStatusCode(this.enableMockSuccess ? 200 : 400);
        return res;
    }
    public MockRemoteSfdcOrgSoqlResponseGenerator(Boolean enableMockSuccess, String testDataset) {
        this.enableMockSuccess          = enableMockSuccess;
        this.testDataset                = testDataset;
    }
}

and invoked within testmethods via

Test.setMock(HttpCalloutMock.class, 
             new MockRemoteSfdcOrgSoqlResponseGenerator(
                       true,'mystaticresourcedatasetname')); 

Note that despite the V31 Apex Developers Guide doc, you can access SObject StaticResource within a testmethod and not need SeeAllData=true

| improve this answer | |

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.