+ Start a Discussion
William Roach-BarretteWilliam Roach-Barrette 

Cant get salesforce to test using mock Web Service callout

No matter what I do I cant get my code to validate using the test methods I made. I want to test a web service callout and already created the test class and static resource that mock uses to make the response. In order to properly test I needed to return the httpresponse I recieved in my desearialize method. This ment I couldnt make it @future(callout=true) so I created another method with the future tag that gets called by my trigger, the test method can call deserialize directly and use it to compare the expected httpResponse to the actual response. But no matter what I seem to do the program wont validate using my test code. It just immeaditally fails saying it cant test webservice callouts. Can anyone offer me a solution that lets me test my respose while maintaining the future callout and in such a way that salesforce will accept it?

WRAPPER:
public class GDPRWrapper{

    public GDPRWrapper(List<GDPRData> templst){
            GDPRList = templst;
        }
    public List<GDPRData> GDPRList {get; set;}

    public class GDPRData {

        public Integer gdprId {get; set;}  //26636
        public String firstName {get; set;}
        public String lastName {get; set;}
        public String email {get; set;}
        public String phone {get; set;}
        public String accountName {get; set;}
        public String contactId {get; set;}    //AA111222333AAAe
        public String emailHash {get; set;}    //78fcb5ad502033c46d35abcecb3615bd92757fb0451485a19b27b7515f6d82d0
        public String createDate {get; set;}   //2018-05-17T15:19:37.000+0000
        public String responseDate {get; set;} //2018-05-21T10:38:53.000+0000
        public String notifyDate {get; set;}
        public boolean marketing {get; set;}
        public boolean security {get; set;}
        public boolean support {get; set;}
        public boolean contactPhone {get; set;}
        public boolean contactEmail {get; set;}
        public boolean contactOther {get; set;}
        public boolean invalid {get; set;}
        
        
    }
   public static List<GDPRData> parse(httpResponse json){
        return (List<GDPRData>) System.JSON.deserialize(json.getBody(), List<GDPRData>.class);
    }
 
    
}

Web callout class:
public class JSONDeserialize {

    public GDPRWrapper wrapper {get;set;}
    public HttpResponse httpResponse {get;set;}
   
    
    @Future(callout=true)
    Public static void firecallout(string str)
    { 
        System.debug('@@@ ' + str);
        JSONDeserialize.deserialize();
    }
    public static HttpResponse deserialize() {
        GDPRWrapper wrapper;
        HttpResponse httpResponse = new HttpResponse();
        
        Http h = new Http();
        HttpRequest request = new HttpRequest();
        
        request.setEndPoint('PRIVATE');
        Blob headerValue = Blob.valueOf('d18849ea4155:d83ce6ef3dbe');
        String authorizationHeader = ('Basic ' + EncodingUtil.base64Encode(headerValue));
        
        
        request.setHeader('Authorization', authorizationHeader);
        request.setMethod('GET');
        HttpResponse response = new HttpResponse();
        try{
        response = h.send(request);
        
        
        System.debug('JSON RESPONSE: ' + response);
        List<GDPRWrapper.GDPRData> obj = GDPRWrapper.parse(response);
        wrapper = new GDPRWrapper(obj);
        
        System.assert(wrapper.GDPRList!=null);
        updateData(wrapper);
        }catch(JSONException j){
                    System.debug('An unexpected error has occured: ' + j.getMessage());
                }
              
        return response;
      }
      
      
      public static void UpdateData(GDPRWrapper wrapper){
        List<Contact> contactPref = new List<Contact>();
        List<Contact> newContacts = new List<Contact>();
          
        for(Integer i = 0; i < wrapper.GDPRList.size(); i ++){
        if(wrapper.GDPRList[i].contactId.length() > 3){
                if(wrapper.GDPRList[i].contactId.subString(0,3) == '003'){
                    Contact toInsert = new Contact();
                    toInsert.firstName = wrapper.GDPRList[i].firstName;
                    toInsert.lastName = wrapper.GDPRList[i].lastName;
                    toInsert.email = wrapper.GDPRList[i].email;
                    toInsert.Email_Hash__c = wrapper.GDPRList[i].emailHash;
                    toInsert.Id = wrapper.GDPRList[i].contactId;
                    toInsert.Sales_and_Marketing__c = wrapper.GDPRList[i].marketing;
                    toInsert.Critical_Security_Notes__c = wrapper.GDPRList[i].security;
                    toInsert.Product_Information__c = wrapper.GDPRList[i].support;
                    toInsert.Contact_Via_Text__c = wrapper.GDPRList[i].contactPhone;
                    toInsert.Contact_Via_Email__c = wrapper.GDPRList[i].contactEmail;
                    contactPref.add(toInsert);
           
                }
            }
        else{
             Contact toInsert = new Contact();
             toInsert.firstName = wrapper.GDPRList[i].firstName;
             toInsert.lastName = wrapper.GDPRList[i].lastName;
             toInsert.email = wrapper.GDPRList[i].email;
             toInsert.Email_Hash__c = wrapper.GDPRList[i].emailHash;
             
             toInsert.Sales_and_Marketing__c = wrapper.GDPRList[i].marketing;
             toInsert.Critical_Security_Notes__c = wrapper.GDPRList[i].security;
             toInsert.Product_Information__c = wrapper.GDPRList[i].support;
             toInsert.Contact_Via_Text__c = wrapper.GDPRList[i].contactPhone;
             toInsert.Contact_Via_Email__c = wrapper.GDPRList[i].contactEmail;
             newContacts.add(toInsert);
        
        
        }
           
            
          
        
        }
          try{
              if(contactPref.size()>0){
                  upsert contactPref;
              }
              if(NewContacts.size()>0){
                  insert NewContacts;
              }          
            } 
            catch(DmlException e){
                    System.debug('An unexpected error has occured: ' + e.getMessage());
                }
      
      }
     }

Test Class:
@isTest
private class JSONDeserializeTest {

        @isTest static void testCalloutEithStaticResource(){
            StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
            mock.setStaticResource('GDPR');
            mock.setStatusCode(200);
            mock.setHeader('Content-Type', 'application/json');
            
            Test.setMock(HttpCalloutMock.class, mock);
            HttpResponse res = JSONDeserialize.deserialize();
            System.assertEquals('PRIVATE DATA', res.getBody());
            System.assertEquals(200, res.getStatusCode());
            System.assertEquals('application/json', res.getHeader('Content-Type'));
        
        
        }


}

Trigger:
 
trigger GDPR_Prefrences_Updater on Contact (after insert, after update) {
   if(System.IsBatch() == false && System.isFuture() == false)
    {
        JSONDeserialize.firecallout('callout fires');
    }

}

Errors:
User-added image
Best Answer chosen by William Roach-Barrette
Ryan GreeneRyan Greene
In order to test Web Callouts you need to create 2 test classes. Basically, one test runs most of the callout code, then uses a mock test to complete the callout. I wrote most of my code from the Apex Documentation, but had to modify the return mock as it was not working properly for me.

ALSO, be sure to add your endpoint to the Remote Site before deploying the change set.

See my example below.
Trigger:
trigger callapplyTrigger on Lead (before update, before insert){
    String ldid;
    if(Trigger.isBefore){
        if(Trigger.isUpdate || Trigger.isInsert){
            for(Lead ld : Trigger.new){
                if(ld.IsConverted == TRUE && ld.Segment__c == 'Large Group'){
                    ldid = ld.Id;
                    if(!Test.isRunningTest()){
                        CallApply.basicAuthCallout(ldid);
                    }
                }
            }
        }
    }
}
Callout Class:
global class CallApply {
    @Future(callout = true)
    public static void basicAuthCallout(String ldid){
        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://yourendpoint');//must also add URL to allowed list in Setup
        req.setMethod('POST');
        String body = '{"ApiKey":"apikeyhere","LeadId":"'+ldid+'"}';
        req.setHeader('Content-Type','application/json');  
        req.setBody(body);
        
        Http http = new Http();
        HTTPResponse res = http.send(req);
    }
}
Test 1:
@isTest
global class Test_callApply1 implements HttpCalloutMock {
    // Implement this interface method
    global HTTPResponse respond(HttpRequest req) {
        // Optionally, only send a mock response for a specific endpoint
        // and method.
        //System.assertEquals('http://example.com/example/test', req.getEndpoint());
        //System.assertEquals('GET', req.getMethod());
        
        // Create a fake response
        HttpResponse res = new HttpResponse();
        res.setHeader('Content-Type','application/json');
        res.setBody('{"example":"test"}');
        res.setStatusCode(200);
        return res;
    }
}
Test 2:
@isTest
private class Test_callApply2 {
    @isTest static void testCallout() {
        // Set mock callout class 
        Test.setMock(HttpCalloutMock.class, new Test_callApply1());
        //create Lead to pass value 'ldid'
        List<Lead> ldtest = new List<Lead>();
        Lead ld = new Lead();
        ld.FirstName = 'testRyan';
        ld.LastName = 'testGreene';
        ld.email = 'testingtrigger1@test.com';
        ld.Company = 'testCompanyasdasdasdeyjhlnn';
        insert ld;
        
        // Call method to test.
        // This causes a fake response to be sent
        // from the class that implements HttpCalloutMock. 
        CallApply.basicAuthCallout('1');
        

        System.assert(true);
    }
}


Documentation here: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_http_testing_httpcalloutmock.htm

All Answers

Ryan GreeneRyan Greene
In order to test Web Callouts you need to create 2 test classes. Basically, one test runs most of the callout code, then uses a mock test to complete the callout. I wrote most of my code from the Apex Documentation, but had to modify the return mock as it was not working properly for me.

ALSO, be sure to add your endpoint to the Remote Site before deploying the change set.

See my example below.
Trigger:
trigger callapplyTrigger on Lead (before update, before insert){
    String ldid;
    if(Trigger.isBefore){
        if(Trigger.isUpdate || Trigger.isInsert){
            for(Lead ld : Trigger.new){
                if(ld.IsConverted == TRUE && ld.Segment__c == 'Large Group'){
                    ldid = ld.Id;
                    if(!Test.isRunningTest()){
                        CallApply.basicAuthCallout(ldid);
                    }
                }
            }
        }
    }
}
Callout Class:
global class CallApply {
    @Future(callout = true)
    public static void basicAuthCallout(String ldid){
        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://yourendpoint');//must also add URL to allowed list in Setup
        req.setMethod('POST');
        String body = '{"ApiKey":"apikeyhere","LeadId":"'+ldid+'"}';
        req.setHeader('Content-Type','application/json');  
        req.setBody(body);
        
        Http http = new Http();
        HTTPResponse res = http.send(req);
    }
}
Test 1:
@isTest
global class Test_callApply1 implements HttpCalloutMock {
    // Implement this interface method
    global HTTPResponse respond(HttpRequest req) {
        // Optionally, only send a mock response for a specific endpoint
        // and method.
        //System.assertEquals('http://example.com/example/test', req.getEndpoint());
        //System.assertEquals('GET', req.getMethod());
        
        // Create a fake response
        HttpResponse res = new HttpResponse();
        res.setHeader('Content-Type','application/json');
        res.setBody('{"example":"test"}');
        res.setStatusCode(200);
        return res;
    }
}
Test 2:
@isTest
private class Test_callApply2 {
    @isTest static void testCallout() {
        // Set mock callout class 
        Test.setMock(HttpCalloutMock.class, new Test_callApply1());
        //create Lead to pass value 'ldid'
        List<Lead> ldtest = new List<Lead>();
        Lead ld = new Lead();
        ld.FirstName = 'testRyan';
        ld.LastName = 'testGreene';
        ld.email = 'testingtrigger1@test.com';
        ld.Company = 'testCompanyasdasdasdeyjhlnn';
        insert ld;
        
        // Call method to test.
        // This causes a fake response to be sent
        // from the class that implements HttpCalloutMock. 
        CallApply.basicAuthCallout('1');
        

        System.assert(true);
    }
}


Documentation here: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_http_testing_httpcalloutmock.htm
This was selected as the best answer
William Roach-BarretteWilliam Roach-Barrette
Thank you for your response and documentation links.By adding the if statement to my trigger that checks if its in a test or not I was able run my program with 0 errors. I also added your implimentation of HttpCallMock.