Testing Batch Job with HTTP Callouts

Suppose I have the following:

global class CMBatchRegisterUsers implements Database.Batchable<sObject>, Database.AllowsCallouts, Database.Stateful {

    global final String orgID = UserInfo.getOrganizationId();
    global final String query;

    global CMBatchRegisterUsers(){
        this.query = 'Select Id,Email from User where IsActive=true';
        System.debug('Organization ID: ' + this.orgID);

    global HttpRequest buildRequest(String email){
        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://www.example.com?user_email=' + email);
        return req;

    global Database.QueryLocator start(Database.BatchableContext bc){
        return Database.getQueryLocator(this.query);

    global void execute(Database.BatchableContext bc, List<User> scope){
        HttpRequest req;
        Http http;
        for(User u: scope){
            http = new Http();
            req = this.buildRequest(u.Email);

    global void finish(Database.BatchableContext bc){}

So far I can test 50% of this code however when I try executing the batch as shown below, I always get System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out.

static testMethod void testBatchRegisterUsers(){
        CMBatchRegisterUsers c = new CMBatchRegisterUsers();
        System.assertEquals(c.orgID, UserInfo.getOrganizationId());

        HttpRequest r = c.buildRequest('test@test.com');
        System.assertEquals(r.getEndpoint(), 'https://www.example.com?user_email=test@test.com');
        System.assertEquals(r.getMethod(), 'GET');

        Test.setMock(HttpCalloutMock.class, new CMMockHttpRegistrationResponseGenerator());
        Database.executeBatch(new CMBatchRegisterUsers());

The error seems to be thrown exactly where I do the http.send(req);.

Can someone point out the proper way to test a batch with callouts in it? My Mock callout doesn’t seem to be helping. Thanks.

Here is the Mock generator as requested.

global class CMMockHttpRegistrationResponseGenerator implements HttpCalloutMock {

    global HTTPResponse respond(HTTPRequest req) {
        // Create a fake response
        HttpResponse res = new HttpResponse();
        res.setHeader('Content-Type', 'application/json');
        return res;

If I change the executeBatch to Database.executeBatch(new CMBatchRegisterUsers(), 1); it throws the error:

System.UnexpectedException: No more than one executeBatch can be called from within a testmethod. Please make sure the iterable returned from your start method matches the batch size, resulting in one executeBatch invocation.


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;
     resp = http.send(req);
     resp = MockApiCalls.WebserviceExpectedResponse();

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.

Source : Link , Question Author : 1337holiday , Answer Author : pjcarly

Leave a Comment