Tuesday, June 11, 2013

In Salesforce, if you are trying to perform a Web Service Callout in a test class, you will get an error. For example:

  1. public String sendHttpRequest(String endpointUrl, String method, DOM.Document body) {
  2.   ...
  3.   HttpRequest req = new HttpRequest();
  4.   req.setEndpoint(endpointUrl);
  5.   req.setMethod(method);
  6.   req.setBody(bodyStr);

  7.   Http http = new Http();
  8.   HttpResponse res = http.send(req);

  9.   return res.getBody();
  10. }

When your test class runs untill line #9, it will stop the entire test process by throwing the following error:

System.TypeException: Methods defined as TestMethod do not support Web service callouts, test skipped callout

What if the overall test coverage is still under 75%? This will become a roadblock for your deployment. Below is the workaround you can consider:

  1. public String sendHttpRequest(String endpointUrl, String method, DOM.Document body, Boolean isTest) {
  2.   ...
  3.   HttpRequest req = new HttpRequest();
  4.   req.setEndpoint(endpointUrl);
  5.   req.setMethod(method);
  6.   req.setBody(bodyStr);

  7.   Http http = new Http();
  8.   if(isTest) {
  9.     HttpResponse res = http.send(req);
  10.     return res.getBody()
  11.   } else {
  12.     // You can prepare some simulated data for your test class here
  13.     return simulatedData;
  14.   }
  15. }

By doing this, you can write different execution as below:

  • Actual Process:
    • You can call the sendHttpRequest method and set the isTest parameter to false.
      • sendHttpRequest(‘your endpoint’, get, ‘http request body’, false);
  • Test Process:
    • In the test process, all you need to do is just set isTest to true.
      • sendHttpRequest(‘your endpoint’, get, ‘http request body’, true);
-->

Friday, June 7, 2013

Testing HTTP Callouts with Static Data in Winter ’13

One of the most eagerly awaited Winter ’13 features, at least for developers, has been the ability to test Apex callouts. You can now test HTTP callouts by either

In this blog entry, I’ll focus on the static resource case. As an example, let’s assume that I’m retrieving JSON Account data from an external service. Here’s a simple callout that retrieves JSON account data, parses it, and returns the resulting list of accounts:

public class CalloutAccounts {
    public static List<Account> getAccounts() {
        HttpRequest req = new HttpRequest();
        req.setEndpoint('http://api.example.com/accounts');
        req.setMethod('GET');
        Http h = new Http();
        HttpResponse res = h.send(req);
        String jsonData = res.getBody();
        List<Account> accounts =
            (List<Account>)JSON.deserialize(jsonData, List<Account>.class);
        return accounts;
    }
}

To test this callout, first, I’ll need to create a file, accounts.json, on my local machine containing test data:

[
  {
    "Name": "sForceTest1",
    "Website": "http://www.sforcetest1.com"
  },
  {
    "Name": "sForceTest2",
    "Website": "http://www.sforcetest2.com"
  },
  {
    "Name": "sForceTest3",
    "Website": "http://www.sforcetest3.com"
  }
]

Now I go to Setup | Develop | Static Resources, click New Static Resource, enter the name jsonAccounts, and select accounts.json for upload. Notice that Force.com set the MIME type based on the extension of the file I uploaded:

Now to define my test method. I’ll use StaticResourceCalloutMock to provide my Account test data when the getAccounts method executes its callout. First, I need to create an instance of StaticResourceCalloutMock and set the static resource, status code and content type header:

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

Now I use Test.setMock to tell the Apex runtime I want to use this instance:

Test.setMock(HttpCalloutMock.class, mock);

Then I can test getAccounts:

Test.startTest();
List<Account> accounts = CalloutAccounts.getAccounts();
Test.stopTest();

And verify I received the expected data:

System.assertEquals(3, accounts.size()); 
System.assertEquals('sForceTest1', accounts[0].Name);
System.assertEquals('sForceTest2', accounts[1].Name);
System.assertEquals('sForceTest3', accounts[2].Name);

So, putting it all together into a test method in a test class:

@isTest
private class CalloutAccountsTest {
    @isTest static void testCallout() {
        StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
        mock.setStaticResource('jsonAccounts');
        mock.setStatusCode(200);
        mock.setHeader('Content-Type', 'application/json');

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

        // Call the method that performs the callout
        Test.startTest();
        List accounts = CalloutAccounts.getAccounts();
        Test.stopTest();

        // Verify response received contains values returned by
        // the mock response.
        System.assertEquals(3, accounts.size());
        System.assertEquals('sForceTest1', accounts[0].Name);
        System.assertEquals('sForceTest2', accounts[1].Name);
        System.assertEquals('sForceTest3', accounts[2].Name);
    }
}

In more elaborate scenarios, I might execute several callouts in a single method. For example, let’s assume I have created a file of JSON-formatted Contact data and uploaded it as the static resource jsonContacts. The method I want to test will retrieve Account data as before, then retrieve the Contacts, and go on to do some processing of the combined Account and Contact data:

public class ProcessAccountsContacts {
    public static String getJSON(String url) {
        HttpRequest req = new HttpRequest();
        req.setEndpoint(url);
        req.setMethod('GET');
        Http h = new Http();
        HttpResponse res = h.send(req);
        return res.getBody();
    }

    public static Integer processAccountsContacts() {
        String jsonData = getJSON('http://api.example.com/accounts');
        List<Account> accounts =
            (List<Account>)JSON.deserialize(jsonData, List<Account>.class);

        jsonData = getJSON('http://api.example.com/contacts');
        List<Contact> contacts =
            (List<Contact>)JSON.deserialize(jsonData, List<Contact>.class);

        // 'Processing'
        Integer result = accounts.size() + contacts.size();
        return result;
    }
}

I’ll create an instance of MultiStaticResourceCalloutMock, configuring it to provide the appropriate static resource data depending on the URL in the callout request. Here’s the test method in its entirety:

@isTest
private class ProcessAccountsContactsTest {
    @isTest static void testCallout() {
        MultiStaticResourceCalloutMock multimock =
            new MultiStaticResourceCalloutMock();
        // 3 test accounts
        multimock.setStaticResource('http://api.example.com/accounts',
            'jsonAccounts');
        // 3 test contacts
        multimock.setStaticResource('http://api.example.com/contacts',
            'jsonContacts');
        multimock.setStatusCode(200);
        multimock.setHeader('Content-Type', 'application/json');

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

        // Call the method that performs the callouts
        Test.startTest();
        Integer result = ProcessAccountsContacts.processAccountsContacts();
        Test.stopTest();

        // Verify response is as expected, given the test data
        System.assertEquals(6, result);
    }
}

So, testing callouts with static data is very straightforward, but what about more complex use cases? I’ll cover the HttpCalloutMock and WebServiceMock interfaces next time out and show you how to create dynamic response data with dependencies on query parameters or the request body.


Click here to view full and original article

Labels

visualforce page ( 13 ) apex integration ( 5 ) apex trigger ( 4 ) csv file from vf page ( 4 ) javascript ( 4 ) csv visualforce page ( 3 ) Too many ( 2 ) call out ( 2 ) integration ( 2 ) rest api ( 2 ) salesforce rest api ( 2 ) salesforce to salesforce integration ( 2 ) sfdc rest api ( 2 ) trigger ( 2 ) 15 digit to 18 digit ( 1 ) DML rows in Apex ( 1 ) Date Conversion ( 1 ) Date/Time conversion ( 1 ) Deploy ( 1 ) Objects to Future Annotated Methods ( 1 ) SFDC limits ( 1 ) Sobject to Future Annotated Methods ( 1 ) Test Class ( 1 ) TimeZone Conversion ( 1 ) Too many dml rows ( 1 ) Too many future calls ( 1 ) annotations ( 1 ) apex code ( 1 ) closed opportunities ( 1 ) commit ( 1 ) convert ( 1 ) create records ( 1 ) csv create records ( 1 ) custom setting ( 1 ) deployment ( 1 ) deployment changeset ( 1 ) disable apex class ( 1 ) disable apex trigger ( 1 ) disable in production ( 1 ) document ( 1 ) download ( 1 ) field name ( 1 ) formula fields ( 1 ) iframe ( 1 ) inactive ( 1 ) intellisense ( 1 ) jsforce ( 1 ) limits ( 1 ) matrix report in vf page ( 1 ) multi select ( 1 ) multi select salesforce ( 1 ) multiselect ( 1 ) paypal ( 1 ) picklist ( 1 ) record type ( 1 ) rollback ( 1 ) salesforce limits ( 1 ) salesforce list ( 1 ) salesforce map ( 1 ) salesforce rest ( 1 ) salesforce set ( 1 ) salesforce1 ( 1 ) sandbox deployment ( 1 ) sfdc collection ( 1 ) sfdc list ( 1 ) sfdc map ( 1 ) sfdc rest ( 1 ) sfdc set ( 1 ) uncommitted ( 1 ) updated field ( 1 ) user ( 1 ) validation rule opportunity ( 1 ) validation rules opportunities ( 1 ) vf page ( 1 )

Ad