1

I am getting a "you have uncommitted work pending" error on a test. Normally this is caused by a DML statement before a callout. That shouldn't be the case here. However, the code runs fine and I am using Test.start and stop appropriately. Im hoping someone can see what I'm missing.

Here's the class:

//Scheduler
public void execute(SchedulableContext sc) {
    DoseSpotRetrieval dsr = new DoseSpotRetrieval(); 
    Database.executebatch(dsr, 30);
}

//Loop over accounts (in batches of 30 so calls dont exceed 100)
public Database.QueryLocator start(Database.BatchableContext BC){
    String query = 'SELECT DoseSpot_Id__c FROM Account WHERE DoseSpot_Id__c != null';
    return Database.getQueryLocator(query);
}

//Handle actual logic
public void execute(Database.BatchableContext BC, List<Account> accounts){
    String doseSpotSystemUser = Label.DoseSpot_System_User;
    String authToken = DoseSpotCallout.GetAuthToken(doseSpotSystemUser);
    getMetadata(); //This is just SOQL

    List<HealthCloudGA__EhrAllergyIntolerance__c> hcAllergies = new List<HealthCloudGA__EhrAllergyIntolerance__c>();
    List<HealthCloudGA__EhrMedicationPrescription__c> hcMedications = new List<HealthCloudGA__EhrMedicationPrescription__c>();

    //Check setup data
    if(String.isBlank(authToken)) {
        System.debug('Failed to get auth token');
        ErrorUtility.CreateSystemLog('DoseSpotRetrieval','GetAuthToken',null,'Failed to get auth token', true);
    }

    for(Account a : accounts) {
        String patientId = a.DoseSpot_Id__c;

        //Get allergies (Documentation section: 3.1.2), convert to records to hcRecords
        String urlEndAllergies = '/api/patients/' + patientId + '/allergies';
        List<Map<String,Object>> allergies = getDoseSpotData(authToken, urlEndAllergies); //CALLOUT HAPPENS IN THIS METHOD. ITS JUST A CALLOUT, NO DML
        ...
        ...
        ...

Here's the test class

@TestSetup
static void makeData(){
    SObjectType sobjType = Schema.getGlobalDescribe().get('Account');
    Map<String, Schema.RecordTypeInfo> acctRTs = sobjType.getDescribe().getRecordTypeInfosByDeveloperName();

    //Insert patient record
    Account patient = new Account(
        Account_Key__c = '123456-09876',
        FirstName = 'FirstName',
        LastName = 'LastName',
        RecordTypeId = acctRTs.get('Sexual_Health_Patient').getRecordTypeId(),
        DoseSpot_Id__c = '12345'
    );
    insert patient;
}

@isTest
static void testHappyPath() {
    Test.setMock(HttpCalloutMock.class, new MockResponse(0));

    Test.startTest();
        DoseSpotRetrieval dsr = new DoseSpotRetrieval();
        dsr.execute(null);
    Test.stopTest();

    List<HealthCloudGA__EhrAllergyIntolerance__c> allergies = [SELECT HealthCloudGA__Account__c,
                                                                DoseSpot_Id__c 
                                                                FROM HealthCloudGA__EhrAllergyIntolerance__c];

    List<HealthCloudGA__EhrMedicationPrescription__c> meds = [SELECT HealthCloudGA__Account__c,
                                                                DoseSpot_Id__c 
                                                                FROM HealthCloudGA__EhrMedicationPrescription__c];

    System.assertEquals(1, allergies.size());
    System.assertEquals('1', allergies[0].DoseSpot_Id__c);
    System.assert(allergies[0].HealthCloudGA__Account__c != null, 'Account was not populated on allergy');

    System.assertEquals(2, meds.size());
    for(HealthCloudGA__EhrMedicationPrescription__c med : meds) {
        System.assertEquals('1', med.DoseSpot_Id__c);
        System.assert(med.HealthCloudGA__Account__c != null, 'Account was not populated on med');
    }
}
0

The documentation states:

The Test.startTest statement must appear before the Test.setMock statement. Also, the calls to DML operations must not be part of the Test.startTest/Test.stopTest block.

You need to change the order of your calls such that Test.startTest occurs before Test.setMock.

5
  • Ive written dozens of tests this way and it works fine
    – Apexing
    Apr 18 '20 at 1:56
  • @Apexing It sometimes works, yes, but not guaranteed. If you do not follow the directions, you risk having this very issue.
    – sfdcfox
    Apr 18 '20 at 1:57
  • Thanks @sfdcfox, I appreciate the info. It looks like it was caused by someone adding DML where I didn't expect it. It seems to be working at the top of the method, but I'll definitely keep an eye out for that going forward.
    – Apexing
    Apr 18 '20 at 2:00
  • @Apexing Yeah, it's good to follow directions. I myself had that issue once, learned the hard way. I'm glad you were able to find the source of the problem, though.
    – sfdcfox
    Apr 18 '20 at 2:01
  • Eh, whatever works...
    – Apexing
    Apr 21 '20 at 20:27
0

DML got added in the ErrorUtility method that was getting called. Should have checked if that had been added before posting. Thanks for viewing all

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.