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);
req.setMethod('GET');
req.setTimeout(60000);
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);
http.send(req);
}
}
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.StartTest();
Test.setMock(HttpCalloutMock.class, new CMMockHttpRegistrationResponseGenerator());
Database.executeBatch(new CMBatchRegisterUsers());
Test.StopTest();
}
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.
EDIT Here is the Mock generator as requested.
@isTest
global class CMMockHttpRegistrationResponseGenerator implements HttpCalloutMock {
global HTTPResponse respond(HTTPRequest req) {
// Create a fake response
HttpResponse res = new HttpResponse();
res.setHeader('Content-Type', 'application/json');
res.setBody('[{"success":true}]');
res.setStatusCode(200);
return res;
}
}
PS.
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.
aaa_
prefix to the class that contains testBatchRegisterUsers(). – Daniel Ballinger May 12 '13 at 20:56uncommitted changes
. I did not alter anything in the database. – 1337holiday May 12 '13 at 20:57