I have review similar questions, and all of them mention to do API before any DML

similar question 1 and similar question 2

However, I am trying to do the API in the excecute, and I am still getting You have uncommitted work pending. Please commit or rollback before calling out but i dont understand why I am getting this, there is no DML aside from Database.QueryLocator in the start, but based on those answer I understood this was still ok to do.

When I run this in the sandbox (no via test method) the batch works correctly.

My class:

// Database.executeBatch(new BatchMinIT5009(), 50);
global class BatchMinIT5009 implements Database.Batchable<sObject>, Database.AllowsCallouts, Database.Stateful {
    global Integer recordsProcessed = 0;
    global Boolean isSandbox;

    global Database.QueryLocator start(Database.BatchableContext bc) {         
        return Database.getQueryLocator(
            'SELECT Id, Loan_Number__c FROM Opportunity WHERE (StageName = \'Loan Funded\')'

    global void execute(Database.BatchableContext bc, List<Opportunity> scope){

        Set<String> scope_JSON = new Set<String>();
        Set<String> oppLoanNumberSet = new Set<String>();
        Map<String, Opportunity> oppLoanNumberMap = new Map<String, Opportunity>();

        for (Opportunity o:scope) {
            oppLoanNumberMap.put(o.Loan_Number__c, o);            

        //MY CALL OUT
        Http http = new Http();
        HttpRequest req = new HttpRequest();
        HttpResponse res = new HttpResponse();
        req.setHeader('Accept', 'application/json');
        res = http.send(req);
        String api_res_body = res.getBody();        
        System.debug('%%% api res \n' + api_res_body); 


    global void finish(Database.BatchableContext bc){
        isSandbox = HelperClass.runningInASandbox();
        AsyncApexJob job = [SELECT Id, Status, NumberOfErrors, 
        TotalJobItems, CreatedBy.Email
        FROM AsyncApexJob
        WHERE Id = :bc.getJobId()];

        String emailBody              = JSON.serialize(job);
        String emailTo                = 'email@email.com';
        String emailSenderDisplayName = 'Saving loans schedules - Original (5009)';
        String emailSubject           = 'Something was wrong, is sandbox: ' + String.valueOf(isSandbox);
        String emailReplyTo           = 'email@email.com';
        if (job.NumberOfErrors > 0) {
            String emailResponse          = HelperClass.emailMethod(emailTo,emailBody,emailSenderDisplayName,emailSubject,emailReplyTo);

My test class:

static testMethod void test_MinIT5009() {

    Map<String, String> responseHeaders = new Map<String, String>();
    responseHeaders.put('Content-Type', 'text/xml');
        Test.setMock(HttpCalloutMock.class, new Test_HttpCalloutMock(200, 'OK', 'OK:^2020-03-04~200~275189|2020-04-04~200~275190|2020-05-04~200~275191',responseHeaders));
        Database.executeBatch(new BatchMinIT5009(), 50);

How are you creating the test Opportunity data... in a @testSetup method?

I've seen some glitchy behaviour resulting from certain combinations of unit tests + callouts + asynchronous Apex + Test.startTest()/Test.stopTest() + Test.setMock + workflow emails or Apex emails. Something confusing happens, in which the behaviour of collapsing async work into one unit test transaction causes a spurious "You have uncommitted work pending" error.

I'm not sure the implementation of your HelperClass.emailMethod but maybe that's similar to what's happening here.

Sometimes to get proper coverage on a Batchable I simply have to test each of its individual methods alone. That might be another way to go.

  • Yes my data is created on @testSetup, even if i dont run HelperClass.emailMethod, I still get the same error, the only time i dont get the error is if I do an API in the start method (before the return) or in the constructor of the class (currently not present), but i did this to test as i need each record been process in the excecution to do the API
    – manza
    Apr 7 '20 at 22:44
  • 1
    The fact that it even fails if you don't run the emailMethod... now that's a stumper. Maybe turn on the finest possible debug log, capture that from the unit test run, and look for any signs of anything it might count as DML.
    – Charles T
    Apr 8 '20 at 14:00
  • 1
    Also is it possible that your @testSetup data creation triggers any workflows/processes that send Email Alerts? That could be a factor in the glitch.
    – Charles T
    Apr 8 '20 at 14:05

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.