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:
@isTest
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
Test.startTest();
CCx_EHR_CMCT_Services.isQueueSendEnabled = true;
Test.setMock(HttpCalloutMock.class, mock);
System.enqueueJob(new QueueSendToRedox(new List<ActivityHL__c>{act}, desk)));
Test.stopTest();
}
Trigger:
trigger HL_ActivityHL_c on ActivityHL__c (before insert, before update, after insert) {
if (Trigger.isAfter) {
if (Trigger.isInsert) {
CCx_ClientDataDomain.sendEHRClinicalComm(Trigger.new);
}
}
}
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
@testVisible
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);
}
}