HTTP Mock Factory. 

We are going to build a HTTP mock factory that is going to help us to mock our unit tests to cover http calls.

Let’s say we have a class that it is executing a http call to an end point in Google.
All we are going to do is to add a search parameter to the engine in order to get a response back.


public class ExternalSearch {
  public class ExternalSearchException extends Exception{}

  public static String googleIt(String query) {
   Http h = new Http();
   HttpRequest req = new HttpRequest();
   req.setEndpoint('https://www.google.com?q='+query);
   req.setMethod('GET');
   HttpResponse res = h.send(req);

     if(res.getStatusCode() != 200){
            throw new ExternalSearchException(
        'Did not received a 200 status code: ' + res.getStatusCode());
     }
     
      return res.getBody();
  }

}

We pass a parameter to the googleIt method with the text we want to search for. The inner custom exception class ExternalSearchException is going to help us latter, as you will see. It is a small detail that really make things easier for us latter.

This is the HTTPMockFactory:
@isTest
public class HTTPMockFactory implements HttpCalloutMock {
    protected Integer code;
    protected String status;
    protected String body;
    protected Map<String, String> responseHeaders;
    public HTTPMockFactory(Integer code, String status, String body, Map<String, String> responseHeaders) {
      this.code = code;
      this.status = status;
      this.body = body;
      this.responseHeaders = responseHeaders;
}
    public HTTPResponse respond(HTTPRequest req) {
      HttpResponse res = new HttpResponse();
      for (String key : this.responseHeaders.keySet()) {
        res.setHeader(key, this.responseHeaders.get(key));
      }
      res.setBody(this.body);
      res.setStatusCode(this.code);
      res.setStatus(this.status);
      return res;
    }
}

We are using protected as access modifier for several variables.

protected: This means that the method or variable is visible to any inner classes in the defining Apex class, and to the classes that extend the defining Apex class. You can only use this access modifier for instance methods and member variables. Note that it is strictly more permissive than the default (private) setting, just like Java.

Now that we have our HTTPMockFactory we can think about building our test class for ExternalSearchException.

@isTest
private class ExternalSearch_Tests {
  
    @isTest static void test_method_one() {
      HttpMockFactory mock = new HttpMockFactory(200, 'OK', 'I found it!', new Map<String,String>());
      Test.setMock(HttpCalloutMock.class, mock);
      String result;
     
      Test.startTest();
      result = ExternalSearch.googleIt('epic search');
      Test.stopTest();
      system.assertEquals('I found it!', result); 
        
    }
      
      @isTest static void test_method_two() {
          
      HttpMockFactory mock = new HttpMockFactory(500, 'Internal Server Error', 'Error 500', new Map<String,String>());
      Test.setMock(HttpCalloutMock.class, mock);
      String result;
      Boolean caught = false;  
          
      Test.startTest();
            try {
                  result = ExternalSearch.googleIt('epic search');
               
            } catch (ExternalSearch.ExternalSearchException e) {
                  System.assertEquals('Did not received a 200 status code: 500', e.getMessage(), 'caught the right exception');
                  caught = true;
                  }
                    System.assert(caught, 'threw expected exception');
           Test.stopTest();  
           system.assertEquals(null , result); 
    }
 }
As you can see this is very straight forward and very easy to modify. Put attention to the way we built or instance to the the Http mock factory:
HttpMockFactory mock = new HttpMockFactory(200, 'OK', 'I found it!', new Map<String,String>());
Those parameters are great to mock our test class in anyway we need to.

Highly recommended Trailblazer module: Unit Testing on the Lightning Platform

Leave a Reply

Your email address will not be published. Required fields are marked *