function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
msaz87msaz87 

Help testing a web service callout for a trigger that doesn't directly request a callout

I'm attempting to include a mock web service callout in a test for a trigger, though the trigger and test don't explicitly execute a callout. I've found this documentation on creating the mock, but I'm pretty new to Apex and am unsure how to configure the two classes: WebServiceMockImpl and WebSvcCallout.

Any guidance would be appreciated. Below is the trigger, an associated class and the current test class.

Trigger:
trigger updateContactAfterConverted on Lead (after update) {
    
        for(Lead lead:System.Trigger.new) {
            
            // was the lead converted?
            
            if (Lead.IsConverted) {
            
                // query new contact
            
                Contact newContact = [SELECT Id FROM Contact WHERE Contact.Id = :lead.ConvertedContactId];
                
                // run @future class to update contact after conversion completed
                
                updateContactAfterConvertedFuture.myMethod(newContact.id);
                
            }
        
        }
    
    }
Associated class:
public class updateContactAfterConvertedFuture {
    
      @future
      public static void myMethod(String newContact) {
    
        // Find new contact
            
        Contact updateContact = [SELECT Id FROM Contact WHERE Contact.Id = :newContact LIMIT 1];
        
        // Set field to true                                    
                                            
        updateContact.Conversion_Completed__c = TRUE;
                        
        // Update contact                
                        
        update updateContact;     
      
       }
    
    }
Test class:
@isTest
    private class testUpdateContactAfterConvertedOrig {
    
        static testmethod void myUnitTest() {

                Test.startTest();
                
        // This causes a fake response to be generated
        Test.setMock(WebServiceMock.class, new WebServiceMockImpl());
        
        // Call the method that invokes a callout
        String output = WebSvcCallout.callEchoString('Hello World!');
        
        // Verify that a fake result is returned
        System.assertEquals('Mock response', output);                 
                
                // Create new test lead
                Lead myLead = new Lead(LastName = 'Fry', Company='Fry And Sons', LeadSource = 'Advertising', Lead_Source_Detail__c = 'PPC');
                insert myLead;
                
                // Convert test lead
                Database.LeadConvert lc = new Database.LeadConvert();
                lc.setLeadId(myLead.id);
                
                // Check conversion
                LeadStatus convertStatus = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted=true LIMIT 1];
                lc.setConvertedStatus(convertStatus.MasterLabel);
                lc.setDoNotCreateOpportunity(True);
                
                // Declare successful
                Database.LeadConvertResult lcr = Database.convertLead(lc);
                Test.stopTest();
                System.assert(lcr.isSuccess());
    
        }
    }

 
Deepak GulianDeepak Gulian
First, implement the WebServiceMock interface and specify the fake response in the doInvoke method.
global class WebServiceMockImpl implements WebServiceMock {
   global void doInvoke(
           Object stub,
           Object request,
           Map<String, Object> response,
           String endpoint,
           String soapAction,
           String requestName,
           String responseNS,
           String responseName,
           String responseType) {

        // Create response element from the autogenerated class.
        // Populate response element.
        // Add response element to the response parameter, as follows:
        response.put('response_x', responseElement); 
   }
}
Have you implemenet this! , in this you are generating fake response. After creating this
Test.setMock(WebServiceMock.class, new WebServiceMockImpl()); // You need to do this in your test class!
 
thatheraherethatherahere

Hi msaz87,

I don't see any Web Service callouts in your class. Why you are including WebServiceMockImpl and WebSvcCallout in your test class? You are just doing a future method call that runs in the background, asynchronously. There is NO Web Service behind this. 

Also you trigger code is not Bulkified. If you will convert large amount of Lead records you are going to face Salesforce SOQL and Future Callouts limitations here. Learn about Execution Governors and Limits here: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_gov_limits.htm (https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_gov_limits.htm" target="_blank)

To Bulkify your code learn about Collections here: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_collections.htm (https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_collections.htm" target="_blank)

Below is the updated version of your code.

Trigger:
Use collection in your trigger. Never do any query or DML inside loop. Never Call a future method inside Loop.

trigger updateContactAfterConverted on Lead (after update) {
    
    list<Id> contactIds = new list<Id>();
    for(Lead ld:System.Trigger.new) {
        
        // was the lead converted?
        if ( ld.IsConverted && ld.ConvertedContactId != null) {
            // Add converted Contact Id into list.
            contactIds.add( ld.ConvertedContactId );
        }
    }

    if( !contactIds.isEmpty() ){
        updateContactAfterConvertedFuture.myMethod( contactIds );
    }

}

Associated class:
public class updateContactAfterConvertedFuture {
    
      @future
      public static void myMethod( List<ID> contactIds ) {
    
        list<Contact> contactsToUpdate = new list<Contact>();

        for( Id contactId : contactIds ){
            contactsToUpdate.add( new Contact( Id = contactId, Conversion_Completed__c = true));
        }    
        
        if( !contactsToUpdate.isEmpty() ){
            update contactsToUpdate;
        }  
    }

}

Test Class:
@isTest
private class testUpdateContactAfterConvertedOrig {

    static testmethod void myUnitTest() {
        // create a Lead
        Lead lead=new Lead(LastName='Doe',FirstName='John',Company='Test',Status='Inquiry');
        insert lead;                

        Database.LeadConvert lc = new database.LeadConvert();
        lc.setLeadId(lead.id);
        lc.setDoNotCreateOpportunity(false);
        lc.setConvertedStatus('Converted');

        Database.LeadConvertResult lcr = Database.convertLead(lc);
        System.assert(lcr.isSuccess());
    }
}

Let me know if you need more Help here.
If my answer meets your needs, Please mark this as SOLVED. This will Help other people here.

Thanks

- thatherahere
 
msaz87msaz87
@thatherahere I'm trying to mock the callout because when I attempt to validate in production, I get the following error: "Methods defined as TestMethod do not support Web service callouts" -- I'm guessing that an existing piece of code is executing a callout during lead conversion, so I wanted to implement the mock to satisfy the test. Does that seem like it makes sense?

Thank you for helping me bulkify my code!