Uncommitted Work Pending in Test with System.runAs?

Question:
I am writing a test class where I need to run the test as two different users, because the approveForm
method contains a validation that prevents the creator of the form from approving it. In my test for approval, I am consistently running into the “Uncommitted work pending” issue, which causes my callout to fail.
Below is my controller code:
@AuraEnabled
public static ChangeAddressForm approveForm(Id caseId) {
ChangeAddressForm form;
try {
form = getForm(caseId);
validateForm(form);
form.successes = new List<String>();
form.errors = new List<String>();
if (isValid(form)) {
Account acc = getAccount(form.data.Scope__c);
if (isSpecialAddress) {
acc.Special_Address1__c = form.customerForm?.specialAddress1;
acc.Special_Address2__c = form.customerForm?.specialAddress2;
acc.Special_Careof__c = form.customerForm?.specialCareof;
acc.Special_City__c = form.customerForm?.specialCity;
acc.Special_Zipcode__c = form.customerForm?.specialZipCode;
}
if (isForeignAddress) {
acc.Foreign_Address1__c = form.customerForm?.foreignAddress1;
acc.Foreign_Address2__c = form.customerForm?.foreignAddress2;
acc.Foreign_Address3__c = form.customerForm?.foreignAddress3;
acc.Foreign_Country_Code__c = form.customerForm?.foreignCountryCode;
}
if (isNameSurname) {
acc.LastName = form.customerForm?.lastName;
acc.FirstName = form.customerForm.firstName;
}
// Webservice callout
IntCust.UpdatePersonAccount(acc, false, isSpecialAddress, isForeignAddress);
form.data = FormService.approveForm(form.data);
update acc;
form.successes.add(FormService.APPROVED_MESSAGE);
}
} catch (Exception e) {
throw CommonUtil.auraException(e);
}
return form;
}
Here is my test method:
@isTest
static void testApproveForm() {
Case testCase = [SELECT Id, AMF_Customer_Id_FF__c FROM Case LIMIT 1];
Account acc = [SELECT Id FROM Account LIMIT 1];
User creatorUser = TestDataFactory.getSysAdminUser();
User approverUser = TestDataFactory.getTestCRMUser();
Test.startTest();
System.runAs(creatorUser) {
Form__c testForm = TestDataFactory.createForm(
testCase.Id,
'ChangeAddress',
acc.Id.toString(),
'Foreign Address;Special Address',
'{"specialZipCode":"54321","specialCity":"Updated City","specialCareof":"Updated Care","specialAddress2":"Updated Special Address 2","specialAddress1":"Updated Special Address 1","lastName":"User","foreignCountryCode":"NO","foreignAddress3":"Updated Foreign Address 3","foreignAddress2":"Updated Foreign Address 2","foreignAddress1":"Updated Foreign Address 1","firstName":"Test"}'
);
}
ChangeAddressForm approvedForm;
System.runAs(approverUser) {
Test.setMock(HttpCalloutMock.class, new TestWSMockCustomer(true));
approvedForm = ChangeAddressFormController.approveForm(testCase.Id);
System.assertNotEquals(null, approvedForm);
}
Test.stopTest();
}
When I run this test, I keep getting the “Uncommitted work pending” error. Why is this happening and how can I fix it?
Answer:
The problem comes from where Test.startTest()
is placed. According to the documentation, any code that executes after calling Test.startTest()
and before Test.stopTest()
is assigned a new set of governor limits. However, if you perform DML (like your TestDataFactory.createForm()
call) inside the startTest()
scope before making a callout, Salesforce throws the “Uncommitted work pending” error because you are mixing DML with callouts.
Master Salesforce with expert-led salesforce online training at CRS Info Solutions—join our demo session now!!!
In your test method, you are creating the form record inside the Test.startTest()
scope. That’s why the callout in approveForm
is failing. To fix this, move the creation of the form outside the Test.startTest()
block, and only wrap the actual approval (which makes the callout) inside Test.startTest()
and Test.stopTest()
.
Here is the corrected test method:
@isTest
static void testApproveForm() {
Case testCase = [SELECT Id, AMF_Customer_Id_FF__c FROM Case LIMIT 1];
Account acc = [SELECT Id FROM Account LIMIT 1];
User creatorUser = TestDataFactory.getSysAdminUser();
User approverUser = TestDataFactory.getTestCRMUser();
System.runAs(creatorUser) {
Form__c testForm = TestDataFactory.createForm(
testCase.Id,
'ChangeAddress',
acc.Id.toString(),
'Foreign Address;Special Address',
'{"specialZipCode":"54321","specialCity":"Updated City","specialCareof":"Updated Care","specialAddress2":"Updated Special Address 2","specialAddress1":"Updated Special Address 1","lastName":"User","foreignCountryCode":"NO","foreignAddress3":"Updated Foreign Address 3","foreignAddress2":"Updated Foreign Address 2","foreignAddress1":"Updated Foreign Address 1","firstName":"Test"}'
);
}
ChangeAddressForm approvedForm;
Test.startTest();
System.runAs(approverUser) {
Test.setMock(HttpCalloutMock.class, new TestWSMockCustomer(true));
approvedForm = ChangeAddressFormController.approveForm(testCase.Id);
System.assertNotEquals(null, approvedForm);
}
Test.stopTest();
}
Explanation:
This test method verifies that the approveForm
logic works correctly when the form is created by one user and approved by another, as required by the validation. First, it runs as the creator user to insert a test form record. Then inside a fresh governor limit context (Test.startTest
), it switches to the approver user, sets up a mock for the external callout, and calls the controller’s approveForm
method. Finally, it asserts that the returned form is not null, confirming successful execution without hitting the “Uncommitted work pending” issue.
Summing Up
This test demonstrates how to properly handle scenarios where one user creates a record and another user must approve it, while avoiding the “Uncommitted work pending” error. The key is placing DML operations, such as form creation, outside the Test.startTest
scope and only executing the approval logic with callouts inside the fresh test context. This separation ensures Salesforce does not block the callout due to pending database operations.
By using System.runAs
, the test simulates two different user contexts, maintaining the business rule that the creator cannot approve their own form. A mocked callout is provided so external integrations do not interfere, keeping the test self-contained and predictable. The final assertion validates that the form approval logic runs successfully, proving the fix is effective.
Unlock Your Future with Salesforce Training in Mumbai
Looking to build a successful career in Mumbai’s growing Salesforce ecosystem? CRS Info Solutions offers expert-led Salesforce online training designed to help you stand out in the competitive job market. Our program covers Salesforce Administration, Development, and the latest AI-powered modules, blending in-depth concepts with real-time projects for practical learning.
Whether you’re starting your Salesforce journey or upgrading your existing skills, our training is tailored to your goals. From mastering certification exams to preparing for interviews, we provide personalized mentorship, detailed course materials, and proven strategies for success.
Don’t wait—join our free demo session today and take the first step toward a rewarding Salesforce career in Mumbai!!!