4

I get an error in my apex test class

You have uncommitted work pending

I am aware of the Salesforce limitation in an http callout, we can't perform any DML operations before we send an http callout.

So, I tried to put the DML in the rest web service (its a little trick but works fine), but the problem is that I still get the same error in my test class.

Code example as follows:

1.Business Logic

  • lock status
  • send http request
  • free status
public class B1 {
    public void foo() {
        Locker__c lk = [SELECT Id,Status__c FROM Locker__c WHERE ...];
        lk.Status__c = 'unavailable';
        UPDATE lk;
        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint(out_webservice_api_url);
        ......
        h.send(req);//it would be throw a error with uncommitted work pending
        lk.Status__c = 'available';
        UPDATE lk;
    }
}

2.Rest Api Code

@RestResource(urlMapping='/internal/update_lock')
public class UpdateLock {
    public static void doPost(Locker__c lk) {
        UPDATE lk;
    }
}

3.Business Code

public class B2 {
    public void foo() {
        Locker__c lk = [SELECT Id,Status__c FROM Locker__c WHERE ...];
        lk.Status__c = 'unavailable';
        String endpoint = 'instance_url/services/apexrest/internal/update_lock/';
        //lock
        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint(endpoint);
        req.setMethod('POST');
        req.setBody(JSON.serialize(lk));
        .......
        h.send(req);
        req = new HttpRequest();
        req.setEndpoint(out_webservice_api_url);
        .....
        h.send(req);
        lk.status__c='avaliable';
        UPDATE lk;
    }

4.test mock class

@IsTest(SeeAllData = false)
global class MyCalloutMock implements HttpCalloutMock {
    global HTTPResponse respond(HTTPRequest req) {
        Locker__c lk = (Locker__c)JSON.deserialize(req.getBody(), Locker__c.class);
        UpdateLock.doPost(lk);
        HttpResponse res = new HttpResponse();
        res.setHeader('Content-Type', 'application/json');
        res.setStatusCode(200);
        return res;
    }
}

5.test class

@isTest
private class B2Test {
    @isTest
    static void unitTest() {
        //
        Test.startTest();
        Test.setMock(HttpCalloutMock.class, new MyCalloutMock());
        B2 b = new B2();
        b.foo();//throw a error
        Test.stopTest();
    }
}

Can anyone help me out?

  • @FJony you can refer this link: salesforce.stackexchange.com/questions/126617/… – Santanu Boral Jul 15 '16 at 4:34
  • You are performing an update in b2 and thus cannot make a callout in b.foo in same transaction. – Eric Jul 15 '16 at 4:35
  • @Eric No,error occurs in the second callout cause first internal callout has performed a dml operations to update locker status in mock class. – F.Jony Jul 15 '16 at 6:17
  • U r correct. I read your naming convention wrong. – Eric Jul 15 '16 at 13:09
1

You can try with the following code:

@isTest
private class B2Test {
    @isTest
    static void unitTest() {
        //
        Test.setMock(HttpCalloutMock.class, new MyCalloutMock());
        Test.startTest();
        B2 b = new B2();
        b.foo();//throw a error
        Test.stopTest();
    }
}

Your issue is already pointed out in previous comments. And the above code will probably resolve your issue by separating them into different contexts via start and stop test.

  • Its also appears same error even move Test.startTest() behind to the SetMock method. – F.Jony Jul 15 '16 at 6:24

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.