I have an after insert trigger that invokes queueable Apex which makes a callout. The trigger and callout work fine in the UI and I don't get any errors in normal operation.

However, my unit test keeps failing with the "uncommitted work pending" error despite all my attempts to separate the callout. I've used a testVisible variable to disable the callout from the trigger so that I can invoke the queueable job explicitly in a startTest/stopTest block after the DML that fires the trigger.

I've pored over the callout class to make sure it's not doing any DML beforehand. Anyway, if it was doing DML, I should get the uncommitted work pending errors in the UI, right? I've tried API version 37 and version 41 but the unit test still fails.

I've had a case open with Salesforce premier support for 6 weeks now but haven't made any progress. Any suggestions?

The unit test:

static void testCallout() {
    // Disable the callout while setting up data.
    CCx_EHR_CMCT_Services.isQueueSendEnabled = false;

    // Set up the data and execute the DML.
    / ...
    insert act;

    // Set up the http mock
    // ...

    // Now enable and execute the callout
    CCx_EHR_CMCT_Services.isQueueSendEnabled = true;
    Test.setMock(HttpCalloutMock.class, mock);
    System.enqueueJob(new QueueSendToRedox(new List<ActivityHL__c>{act}, desk)));



trigger HL_ActivityHL_c on ActivityHL__c (before insert, before update, after insert) {
    if (Trigger.isAfter) {
        if (Trigger.isInsert) {

Trigger handler class:

public without sharing class CCx_ClientDataDomain {
    public static void sendEHRClinicalComm(List<ActivityHL__c> triggerNew) {
    // do some processing here.
    // ...
    // then queue the callout job.
    System.enqueueJob(new CCx_EHR_CMCT_Services.QueueSendToRedox(
            deskActivities.get((Id) desk.getDeskId()), desk));

Queueable job class with callout method:

public with sharing class CCx_EHR_CMCT_Services {
    // isQueueSendEnabled is an attempted workaround for unit tests
    private static Boolean isQueueSendEnabled = true;

    public class QueueSendToRedox implements Queueable, Database.AllowsCallouts {
        private List<ActivityHL__c> activities;
        private CCx_DeskHierarchySelector.Desk desk;
        private Boolean isEnabled;

        public QueueSendToRedox(List<ActivityHL__c> activities, CCx_DeskHierarchySelector.Desk desk) {
            this.activities = activities;
            this.desk = desk;
            this.isEnabled = isQueueSendEnabled;

        public void execute (QueueableContext context) {
            if(this.isEnabled) sendClinicalCommToRedox(activities, desk);

    public static void sendClinicalCommToRedox(List<ActivityHL__c> activities, CCx_DeskHierarchySelector.Desk desk) {
        // Set up data for the callout.  No DML actions are executed before the callout.
        HttpRequest req = buildRequest();
        // ...

        // Callout
        Http http = new Http();
        HttpResponse resp = http.send(req);

1 Answer 1


You'll need to test the method directly, and test the Queueable separately. The easiest way to do so is a static flag.

public class MyQueueable implements Queueable
    @TestVisible static Boolean makeCallout = true;
    public void execute(QueueableContext context)
        if (makeCallout) performCallout();
    public static void performCallout()
        // make callout here

Testing the job:

MyQueueable.makeCallout = false;
// enqueue job

Then test your method which actually makes the callout separately:


The reason you get this error is that when you enqueue the job, that counts as a DML Operation. Then when you call Test.stopTest(), it runs synchronously, making a callout within the same transaction.

  • 1
    Many thanks @Adrian! This has been a big headache for weeks and Salesforce premier support couldn't come up with the answer. Dec 29, 2017 at 0:51
  • 9
    Looks like a bug, Queuable Apex/future was designed to allow callouts after DML, But testing framework kinda defeats its purpose. Today I wasted 4-5 hours investigating this, it should be part of the documentation. Mar 1, 2018 at 1:47
  • I have it other way around: my primary class is calling API page-by-page in a while loop, and then sends received chunks to a queued job for processing (and that job is doing DML). Each job is ought to have separate execution context, so, it should be ok, and this is why I needed them jobs in the first place, but it looks that in tests they all share one context… :(
    – pilat
    Sep 29, 2022 at 8:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .