3

i am having an issue in how to write a test class for APEX REST service that is having a callout to another external webservice.

REST Service Code:

@RestResource(urlMapping='/Registration/*')

global with sharing class Registration{

    @HttpPost
    global static String registerNewUser(String FirstName,String LastName, String Email, String CompanyName,String PostalCode,String CompanyNumber,String UserName,String Password,String EncryptedPassword,String Country)
    {
        //get the above input parameter
        //create a lead and convert it to contact
        //create a portal user from the contact
        //if portal user creation = success then
        //call a future method with some input parameters
        //the future method instantiate a proxy class and invoke actual webservice method
     }

Issues we are getting:

  1. You have uncommitted work pending. Please commit or rollback before calling out

Please can someone help on how to tackle this issue...

Thanks in advance... Baskaran

1

2 Answers 2

4

When testing HTTP callouts in Apex, I generally have a Helper Class, with static methods which returns the response I am expecting from the webservice, and in my code, where the http.send(); would normally go, I use this instead.

HTTPResponse resp;
if(!Test.isRunningTest())
{
     resp = http.send(req);
}
else
{
     resp = MockApiCalls.WebserviceExpectedResponse();
}

Mock Calls class Example

public class MockApiCalls
{

    public static HttpResponse WebserviceExpectedResponse()
    {
        HttpResponse httpResponse = new HttpResponse();
        httpResponse.setStatusCode(200);
        httpResponse.setBody('{"message":"success","cost":0.09600000000000000}');
        return httpResponse;
    }
}

I know this isn't particularly clean, but unfortunately this seems to be the only way to properly test http callouts for now. There seem to be improvement coming in the future, in the last release they included Testing Web Service Callouts but you still get the problems you are facing

System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out

This is because in test deployments, all tests still run in one context, and you run into the Cannot do a DML statement before doing a webservice callout problem.

Second Option

This only works when you only have 1 webservice callout to test in your entire test code.

You can name your test class which does the webservice testing AAATestClass. Which causes your test to be executed before all the rest, and you don't run into the earlier mentioned problem. This is because tests are ordered by test class alphabetically and executed in that order.

2
  • Hi PJC, Thanks for your reply. can you please explain a little bit the line of code resp = MockApiCalls.WebserviceExpectedResponse(); i did not get it. May 29, 2013 at 15:48
  • I added the MockApiCalls class to the answer.
    – pjcarly
    May 30, 2013 at 7:21
1

Use HttpCalloutMock for the test and either move the callout (the actual call to the webservice) to a future method (a method annotated with @future), which will run asynchronously, or, if you are using a Batch (batch processes cannot call futures), make the Batch implement Database.AllowsCallouts.

For the future, since the method will make a callout you have to add the callout=true parameter. Thus the final method will look something like:

@future(callout=true)
public static void myFutureMethodThatCallsAWebService(params) {
    ...
}

It will look like this for the Batch:

global class SearchAndReplace implements Database.Batchable<sObject>, Database.AllowsCallouts {
    ...
}

You must log in to answer this question.

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