Unit Test: You have uncommitted work pending. Please commit or rollback before calling out

  • So I have a method that takes as a parameter an Id of a object and uses it to make an external callout. Unfortunately I can't seem to figure out any way to test it.

    @isTest static void sometimes_salesforces_sucks() {
       My_Object__c foo = new My_Object__c(Name='test');
       insert foo;
       MyClient client = new MyClient();
       MyMockResponseGenerator mockResponse = new MyMockResponseGenerator();

    This question says that using start/stop test should work, but it doesn't work for me

    Can you post your code? When is your callout initiated in code?

    This pattern works for me. Two things you could check: 1) that there are no callouts made as a side effect of any code before Test.startTest; 2) that there are no updates made before the callout within the bar method. (One example of a "hidden" update would be a class that automatically inserts uninitialised custom settings when a setting value is referenced for the first time.)

    @greenstork sorry i thought that was obvious. client.bar();

    @KeithC, checked all of those things... still no go

    @greenstork the code is long and complex (so I'd rather not post and try to explain it) but there are no DML operations before any callouts in "client.bar(foo.Id)"

    If you capture a debug log when running the test, what was the last thing to occur before the test fails?

    Try to use @isTest(SeeAllData=true), and use an existing foo id (remove the insert of foo from test), if that solve the problem, then the insertion of foo doing something else (maybe a trigger). By the way I have objects that were inserted before the test (like your foo) which didn't had any trigger or something that related to the call out, but yet by insert them the uncommited work pending error produced, if that will be the case the only solution I have found is to use the old method of bypass call out in test --> Test.isRunningtest() (do something else when testing)

    I ended up just bypassing the callout. I'm testing the callout directly in another place so i don't lose any code coverage. just feels hacky...

    Before making a callout ensure you do not have any insert/update/delete DML statements. Try to make the callout.

    @NSjonas - You answer is below. It is simply moving the mock lines after the test.starttest

    @NSjonas - Did you try the answer below? Please update or close the question out by accepting the answer. Hate to see you architect at "workaround" just because you cannot get it to work. Lets get it done the right way for ya. I also noticed they fixed the error when doing a callout during a batch and that Mock implementation now works correctly in Winter 16

    @NSjonas, I have the same problem. Interestingly, it is caused by one type of object. When I insert it - fail. does not insert it - fine (no uncommitted error). Magic... However, this object is from unmanaged package.

    Running into this issue, but only when I started inserting a test user. Inserting other objects worked perfectly fine when performed before the callout and don't result in a callout exception

  • You can't do a web service callout after a DML operation in the same transaction. try this code:-

    @isTest static void sometimes_salesforces_sucks() {
       My_Object__c foo = new My_Object__c(Name='test');
       insert foo;
       MyClient client = new MyClient();
       Test.setMock(HttpCalloutMock.class,new MyMockResponseGenerator());

    You cannot perform a DML operation prior to a callout. All the DML operations should be invoked only after you are done with callouts.So, make a webservice callout first and then save the request.

    If you are making multiple callouts, then save all the requests in a list or map and post callouts you save them.

    Basically the following scenario will work :-

    query callout query callout insert

    callout callout callout insert or update

    But the following scenario will fail :-

    callout insert callout <---- fails="" here="" p=""> Possible workaround :-

    splits the transaction into two separate Ajax processes. The first inserts the record and the second performs the callout and is able to update the newly inserted record.

    You comment and your code are a bit conflicting. You are correct but you need to add why your code works so the OP can understand it.

    I'm having the same problem. One way it doesn't fail - comment out static initialization section, where I make a bunch of insert/update DMLs. Also, my test is the same as @NSjonas has. Surrounded by Test.startTest()/Test.endTest().

    This isn't always true, I've got loads of tests that make callouts with a mocked response, and those can happen after I've inserted test data.

    Does this work for you? Since this doesn't work for me. There is definitely some bug in Salesforce which is still not fixed, so these workaround do not work.

    Did you open Salesforce Support case describing the issue you are facing? If you don't do this, there is a chance that the issue will never be fixed and developers will have to use workarounds forever.

  • There were several Salesforce issues related to

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

    Besides of the issues mentioned, additional issues that I have encountered with, were:

    1. The problem with @future(Callout=true) methods. First time I reported this was at February 12, 2015 Spring 15 Release (v.33)

    2. There was a known issue, which was claimed to be fixed in the next year, however, it wasn't really fixed. I have opened another Salesforce support case, they told me the work id of it was "W-3171561" but they never provided a list to known issue and I was promised to be notified once this issue is resolved, however, I was never notified on this issue resolution.

    3. Later I suggested a workaround for this long-running issue to downgrade the apex class version to 28.

    4. As of Summer 2019 release (version 46) I can't reproduce the future callout issue anymore. However, I have found another issue, the reasons for which are not clear to me. It is somehow related to user trigger and batch or queueable jobs. I have opened another Salesforce support case for this. Let's see how this goes. I have posted about this issue today on my blog


    There is some constant long-running ever-lasting bug related to uncommitted work pending. It is hard to find and reproduce it. Every time when Salesforce makes some change to this implementation, it becomes harder to debug and to troubleshoot it, but the core issue is still present.

    Some workaround might be applicable for this issue.

    1. Try to downgrade the class version to 28.0 or older where issue wasn't introduced yet (the version should be older than Spring 15).

    2. Try to move the setup code into method annotated with @testSetup annotation. It is not clear why, however, in many cases this helps to workaround this issue

    Update: This is the known issue https://success.salesforce.com/issues_view?id=a1p3A000000ATF1QAO, we need subscribe to it and wait for a fix or use some workaround meanwhile if applicable

    I have the same issue. Unit test works ok if I don't insert a user record in test data. If I insert a user then callout in a queueable doesn't work - throws the same 'you have uncommitted work pending' error. Moving the data setup to a @TestSetup method doesn't fix the issue, couldn't find any workaround and will have to find a different way to test the code... :/

    @sskular I think you are affected by this known issue https://success.salesforce.com/issues_view?id=a1p3A000000ATF1QAO subscribe to it and wait for a fix or use some workaround meanwhile

    If my customer didn't want salesforce I would never use it. This has to be the WORST framework for building production grade applications I have EVER run across! How on earth are they such a large and successful company with such BAD software?

    @SoftwareSavant I feel your pain, bro.

    I still have this issue even after the Spring '21 release.

  • At the moment of writing (June 2019), unit tests are not always working as expected when it comes to libraries/folders/files. Code running fine 'live' may throw exceptions like that in unit tests.

    What is probably going on, my guess, is that deep under water storage is not fully in the database but also partly on a file system. Then, a lot of magic happens with ContentXxxxx objects to make it appear as if we deal with standard SObjects. Think of creation of a ContentDocument on insert of a ContentVersion, or creation of a ContentFolderMember to the root folder of a library if you create a new ContentDocumentLink.

    Creating those 4 objects does not work in a unit test though.

    Things you try in the unit tests (which have to be rolled back after the test) may not behave the same as in actual execution. It may save you a lot of time to isolate the ContentXxxxx functionality, and leave it in the 25% untested code Salesforce allows you. The test outcome you get is not assured to be representative of the production behavior at the moment yet. Just make sure it works fine by other means.

    It may sound a bit negative, but then I just spend two days too trying to work around the issues. :-)

    Did you open Salesforce Support case describing the issue you are facing? If you don't do this, there is a chance that the issue will never be fixed and developers will have to use workarounds forever.

  • After playing around with it a bit, I found the following worked for me:

      ALL DML and *queries* (I found this necessary, as well) goes here
      Test.startTest(); // before Test.setMock
      Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator());

    I don't believe this is correct, and appears to be no different from what the OP started with. Queries should be able to be placed anywhere. This answer would probably be improved by going into more depth about how it works (if you do add explanation, please make it an [edit] to your answer).

    @DerekF This is different than what the OP stated. The OP had put"Test.setMock(..)" before "Test.startTest()". During testing, I found that this is what made the difference. I also found that if it queried for the records after Test.startTest(), it also threw the same exception. Please test and if you find the result as I stated, remove this downvote. I believe this can be very helpful. I don't how it works, I know that it does work, and that's what matters.

    @DerekF As an aside, I think this kind of gatekeeping is unhelpful for the community. I had the same issue as the OP, solved it, and took time out of my day to help the broader community. I don't need the status points Stack Overflow gives, just trying to help.

  • I got the same issue. Fixed it by creating Mock Data within Test.StartTest and Test.StopTest. Note: Test.LoadData is inserting test data from Static Resource CSV.

        List<Account> accList=Test.loadData(Account.sObjectType,'challengeAccounts');AccountListController controller = new AccountListController();     
        // Set mock callout class
        Test.setMock( HttpCalloutMock.class, new OpportunityMockHttpResponseGenerator() ); 

    Did you open Salesforce Support case describing the issue you are facing? If you don't do this, there is a chance that the issue will never be fixed and developers will have to use workarounds forever.

  • After much searching, I think I found an interesting solution that might have a general application. At the end of the day, this error is triggered by the fact that you have a DML and a callout in the same transaction. You can't force a commit (ie: you can't arbitrarily decide when the transaction ends), but you can make sure you generate your Test Data in a separate transaction. Here's how: use @testSetup

    Use test setup methods (methods that are annotated with @testSetup) to create test records once and then access them in every test method in the test class

    By creating all your test Data in @testSetup (or by loading static resources with loadData), you are keeping them in a separate transaction, and then you can do all the callouts your heart desires.


  • This answer won't offer anything new by way of an explanation for why this is happening, but it may offer another solution for those who are struggling with the issue.

    I started getting this error on a test method that was previously passing. The interesting thing was -- I hadn't made any changes to that method whatsoever. I was making what I thought were unrelated changes, implementing a @TestSetup method in the class, and making other methods in the class more efficient.

    I ended up splitting my method out into a separate test class, and now it's working fine.

License under CC-BY-SA with attribution

Content dated before 7/24/2021 11:53 AM