Unit tests that need more than one WebServiceMock

I’m dealing with an odd situation where I need to call Webservice A to authenticate to Webservice B and Webservice C, all with different endpoints. I know how to setup mocks to test B and C individually, but I can’t do that for my real tests. The workflow is:

  1. User loads a VF page
  2. On load, VF page calls B.someMethod()
  3. B.someMethod needs to first call A.getAuthToken()
  4. Use authToken to complete call to B.someMethod()

I know that I could create one mock class to handle all of the web services (or at least to fake the authentication), but that could be very cumbersome to maintain given that B and C both have dozens of methods.

Is there a better way to handle unit tests where each method needs to provide a mock for multiple endpoints?

Note: These are JSON-based web services, and not SOAP.

Answer

The doInvoke method on the mock interface passes in the stub and request parameters. You can use these to condition to dispatch the mock logic to various other mock implementations, while only registering a single mock implementation.

Test.setMock(WebServiceMock.class, new MockDispatcher());

public class MockDispatcher implements WebServiceMock 
{
    public void doInvoke(
        Object stub, Object request, Map<String, Object> response,
        String endpoint, String soapAction, String requestName,
        String responseNS, String responseName, String responseType) 
    {
        if(stub instanceof A)
            new AMock().doInvoke(
                stub, request, response, 
                endpoint, soapAction, requestName, 
                responseNS, responseName, responseType);
        else if(stub instanceof B)
            new BMock().doInvoke(
                stub, request, response, 
                endpoint, soapAction, requestName, 
                responseNS, responseName, responseType);
        return;
    }
}    

public class AMock 
{
    public void doInvoke(
        Object stub, Object request, Map<String, Object> response,
        String endpoint, String soapAction, String requestName,
        String responseNS, String responseName, String responseType) 
    {
        if(request instanceof A.GetAuthTokenRequest_element)
            response.put('response_x', new A.GetAuthTokenResponse_element());
        return;
    }
}    

public class BMock 
{
    public void doInvoke(
        Object stub, Object request, Map<String, Object> response,
        String endpoint, String soapAction, String requestName,
        String responseNS, String responseName, String responseType) 
    {
        if(request instanceof B.SomeMethodRequest_element)
            response.put('response_x', new B.SomeMethodResponse_element());
        return;
    }
}    

Attribution
Source : Link , Question Author : Mike Chale , Answer Author : Andrew Fawcett

Leave a Comment