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?

4
  • @FJony you can refer this link: salesforce.stackexchange.com/questions/126617/… Jul 15, 2016 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, 2016 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, 2016 at 6:17
  • U r correct. I read your naming convention wrong.
    – Eric
    Jul 15, 2016 at 13:09

1 Answer 1

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.

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

You must log in to answer this question.

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