function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
MaxSilveraNMaxSilveraN 

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

Hello Everyone,

I've been trying to do a test Method for a callOut class that invokes a Callout in a future Method, but this is returning System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out only in the test Execution, When running in the normal flow, it responses with no problem.

I've understood that this error is produced when doing a DML statement before a CallOut. However there's no operation besides the createData in the TestSetUp.

I've read some posts and the most likely was this one:  https://developer.salesforce.com/forums?id=906F0000000927CIAQ  .But the proposed solution of Test.StartTest();  Test.SetMock(); ... Test.EndTest()  is already developed.

This is the code returning the error
@isTest
global class RPP_SyncOportunidad_ws_tst {
    
    @testSetup
    static void createData()
    {
        Account acc = new Account();
        acc = new Account();
 		acc.Name='AVX_cuentaPrueba ';
        acc.RPP_NombreComercial__c='NombreComercial '; 
        insert acc;
        
        Contract contrato =  RPP_DataGenerator_cls.crearContrato(true, acc.Id);
        Opportunity objOpp = RPP_DataGenerator_cls.crearOpportunity(false,acc.Id);
        objOpp.RPP_Acuerdo__c= contrato.Id;

        insert objOpp;
    }
    
    public static testMethod void successTest()
    {
        List<Opportunity> lstOpps = [SELECT Id FROM Opportunity];
        Test.startTest();
        Test.setMock(HttpCalloutMock.class, new MockSuccessResponse());
        RPP_SyncOportunidad_ws mci = new RPP_SyncOportunidad_ws(lstOpps);
        Id jobId = System.enqueueJob(mci);
        Test.stopTest();
        
        System.assertNotEquals(mci, null, 'Test error: Cannot create invocacion ws');
    }
    
    global class MockSuccessResponse implements HttpCalloutMock
    {
        global HTTPResponse respond(HTTPRequest req)
        {
            HttpResponse res = new HttpResponse();
            res.setHeader('Content-Type', 'application/json');
            String strJSON ='[\n' +
                '{\n' +
                ' "CodigoError": null, \n' +
                ' "EntidadComercialId": "32201", \n' +
                ' "Estado": "S", \n' +
                ' "Mensaje": "Cliente registrado con éxito", \n' +
                ' "SalesForceGuid": "D58B1521-BAC2-4279" \n' +
                '}\n' +
                ']';                          
            res.setBody(strJSON);
            res.setStatus('OK');
            res.setStatusCode(200);
            return res;
        }
    }
}
It also happens that I have developed other CallOut classes with their own TestClasses and they work just fine.

Has anyone being in this issue?
Raj VakatiRaj Vakati
You need to use the  if(!test.isrunningtest()) in your main class 

 
if(!Test.isRunningTest()){
     YOUR INtegatin or API cal 
}   else{

String DummyResp = '{"example":"test"}';
return DummyResp ;
}

 
MaxSilveraNMaxSilveraN
Hello Raj,

I used to Test.isRunningTest(), to set the Authentication on the headers, which is an actual call to another service. 
The Main Class who does the service falls in the Http protocol send when running the test
 
Http httpProtocol = new Http();
HttpRequest request = new HttpRequest();
HttpResponse response;
request.setHeader('Content-Type', 'application/json');
            
request.setHeader('Authorization', token);   //already define as a String
request.setEndPoint(wsSettings.RPP_EndPoint__c);  //The EndPoint points to the MockCallOut
request.setMethod('POST'); 
request.setBody(jsonOrders);  //contains the body for the request
response = httpProtocol.send(request);   //Here's where the TestMethod fails
            
System.debug('ResponseAfter::'+response);
String RespuestaSw = response.getBody();
String estatus = response.getStatus();
            
if(estatus == 'OK')
{
         //logic if return Success

}
The message for the response is given in the MockSuccessResponse in the TestClass.
In other Callouts classes, it returns the Test HttpResponse succesfully, but because of the uncomitted work pending error it breaks during test.
 
v varaprasadv varaprasad
Hi,

Try this:

 
public static testMethod void successTest()
    {
        List<Opportunity> lstOpps = [SELECT Id FROM Opportunity];
        Test.setMock(HttpCalloutMock.class, new MockSuccessResponse());
		
		Test.startTest();        
			RPP_SyncOportunidad_ws mci = new RPP_SyncOportunidad_ws(lstOpps);
			Id jobId = System.enqueueJob(mci);
        Test.stopTest();
        
        System.assertNotEquals(mci, null, 'Test error: Cannot create invocacion ws');
    }


Hope this helps you!
If my answer helps resolve your query, please mark it as the 'Best Answer' & upvote it to benefit others.


Thanks
Varaprasad
Salesforce Freelance Consultant/Developer/Administrator
@For Salesforce Project Support: varaprasad4sfdc@gmail.com


Salesforce latest interview questions  :
https://www.youtube.com/channel/UCOcam_Hb4KjeBdYJlJWV_ZA?sub_confirmation=1

 
MaxSilveraNMaxSilveraN
Hello varaprasad

I've tried what you suggest but didn't work. What I am doing is to divide the main class in different methods so I avoid doing the covering of the execute method of the Queueable Interface; that's the only way I can do it by now, until I find how to correct it.
Dev_AryaDev_Arya
If Anyone stuck at this page, this is a known issue with salesforce and there is currently no workaround for the issue. This is the status from July 2020
Issue link - Uncommited work (https://trailblazer.salesforce.com/issues_view?id=a1p3A0000003UWIQA2&title=uncommitted-work-pending-exception-on-callout-test-from-async-apex)