I am attempting to test a @future callout class that pings another class to make an API call and update some fields in the Lead object. I am using the mock http method and here's the script:

private class MMarkAPITest
    static void MMarkAPIUnitTest() {

        //create a lead with website address of testapp.com
        Lead l = new Lead
        (company = 'Test Company',
        status = 'Open',
        website = 'testapp.com',
        firstname = 'Guy',
        lastname = 'Test');
        insert l;

        //set-up a mock callout
        Test.setMock(HttpCalloutMock.class, new MMarkAPITestHttpCalloutMock());
        // Call method to test.
        // This causes a fake response to be sent
        // from the class that implements HttpCalloutMock.


        //access the lead entity
        Lead updatedLead = [select Name, Country, Description from Lead where Id = :l.Id];

        System.debug('lead is ' +updatedLead);

        System.assertEquals(l.description, 'description');
        System.assertEquals(l.MZ_Lo__c, 'country');
        System.assertEquals(l.YY_Totag__c, 'total funding');


However when running it with System.assertEquals it fails (all assertions return null value).

On the other hand, when I remove the System.assertEquals the test succeeds but also returns the following message:

System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out

I came across some information regarding DML queries and testing callouts (e g here), but I am struggling to apply it to this problem.

Adding the FutureCallUpdater:

public static void MMAPIFutureCallUpdater(string domain){

This triggers that:

public static void MMAPIUpdater(string domain){
    list<Lead> leads = [SELECT MM_Description__c FROM Lead WHERE Website LIKE :domain limit 1];

    HttpResponse res = MMAPIcallout(domain);

    if(res.getStatusCode() == 200 && string.isNotBlank(res.getBody())){

      string body = res.getBody();
      //system.debug('body before replaced is'+body);
      body = body.replace('"currency":', '"deal_currency":');
      //system.debug('body after replaced is'+body);

      JSON2Apex companyProfile = MMAPIParse(body);
      system.debug('company profile is' +companyProfile);

      //single ocurring variables
      string description = companyProfile.data.description;
      //system.debug('description is'+description);
      string country = companyProfile.data.country;
      //system.debug('location is'+country);
      string employees_current = companyProfile.data.employees;
      //system.debug('employees_current is'+employees_current);
      string employees_month_ago = companyProfile.data.employees_month_ago;
      //system.debug('employees_month_ago is'+employees_month_ago);
      string employees_6_months_ago = companyProfile.data.employees_6_months_ago;
      string total_funding = companyProfile.data.total_funding;
      //system.debug('total_funding is'+total_funding);
      string last_funding_amount = companyProfile.data.last_funding_amount;
      //system.debug('last_funding_amount is'+last_funding_amount);
      string last_funding_date = companyProfile.data.last_funding_date;
      //system.debug('last_funding_date is'+last_funding_date);

      //convert list variables into strings

      List <String> businessModels = companyProfile.data.business_models;
      string commaSeparatedBusinessModels = '';
      if(businessModels != null){
        //system.debug('the business models list it' +business_models);
        for (String model:businessModels ){
          commaSeparatedBusinessModels += model + ', ';
        //system.debug('comma separted business models are'+commaSeparatedBusinessModels);

      List <Meta> acquiredBy = companyProfile.data.acquired_by;
      string commaSeparatedAcquiredBy = '';
      if(acquiredBy != null){
        for (Meta acquirer:acquiredBy){
          commaSeparatedAcquiredBy += acquirer + ', ';

      // singular variables to be inserted into Lead objects
      for(Lead l:leads){
        l.MM_Business_Models__c = commaSeparatedBusinessModels;
        l.MM_Description__c = description;
        l.MM_Location__c = country;
        l.MM_employees_current__c = employees_current;
        l.MM_employees_1M_Ago__c = employees_month_ago;
        l.MM_employees_6M_Ago__c = employees_6_months_ago;
        l.MM_Total_Funding__c = total_funding;
        l.MM_Last_Funding_Amount__c = last_funding_amount;
        l.MM_Last_Funding_Date__c = last_funding_date;
        l.MM_Acquirers__c = commaSeparatedAcquiredBy;

      try {
        update leads;
      }   catch (DmlException e) {

      //lists of variables to be inserted into custom objects



      To ensure deals are added only once (no duplicates), the script invokes the lead with the relevant ID number
      (obtained by looking for a lead with the relevant domain) and creates a string of funding deal dates (dealDatesInString)
      separated by a comma. Subsequently, upon lead update only funding rounds with the date
      not appearing on the list are added to the Lead (if (!dealDatesInString.contains(deal.funding_date))


      string LeadId = getLeadID(domain);
      List <Funding> funding = companyProfile.data.funding;
      List<MM_Funding_History__c> dealsList = [SELECT MM_Date__c FROM MM_Funding_History__c WHERE MM_Funding_History_To_Lead__c = :LeadId];
      //system.debug('the list is' +dealsList);

      //ensuring that the deals are added only once
      string dealDatesInString = '';
      for (MM_Funding_History__c d :dealsList){
        dealDatesInString += d + ', ';
      //system.debug('deal dates string is' +dealDatesInString);

      for(Funding deal:funding){
        //ensuring deals are added only if they're not already on the list (using MM_Date__c as unique identifier)
        if (!dealDatesInString.contains(deal.funding_date)){
          MM_Funding_History__c row = new MM_Funding_History__c(
          MM_Funding_History_To_Lead__c = getLeadID(domain),
          MM_Amount__c = deal.amount,
          MM_Date__c = deal.funding_date,
          MM_Funding_Type__c = deal.series,
          MM_Investors__c = deal.investors,
          MM_Currency__c = deal.deal_currency);
          //system.debug('this is row' +row);
          insert row;

  • 1
    Can you post MMarkAPIFutureCallUpdater – EricSSH Jun 13 '17 at 16:58
  • You need to query all fields which you want to check in assert method. I can see you are querying some fields but those are being assigned into 'updatedLead' variable, but in assert method you are using old instance variable to check. – RSG Jun 13 '17 at 17:12
  • @RSG that's valid, but not the problem right now – EricSSH Jun 13 '17 at 17:22
  • I've hit issues before (actually today again) where other things get triggered by the stoptest, causing DML to fire, and giving you that error. e.g. I had a test fail for the same reason as yours because workflow was creating a task on creation of a record - and for some reason I can't discover, that was causing DML to happen. Disable the workflow, and it worked. There have also been historical issues with email alerts causing the uncommitted error in tests. So I would look at other actions that happen on create lead, and see if you can track down the rogue DML – BritishBoyinDC Jun 14 '17 at 0:02
  • 1
    @BritishBoyinDC - I've seen this as well with ProcessBuilder seemingly executing as part of the Test.stoptest and hence in the same transaction as the future causing the UncommittedWorkpending error. One expected the Process Builder to run before test.stoptest. Workaround was to avoid executing the process builder flow in the testmethod by avoiding its entry conditions – cropredy Jun 15 '17 at 17:23

Your Answer

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

Browse other questions tagged or ask your own question.