3

I have set-up an APEX class that uses a web service callout to create a PDF and attach it to a contact record. However, I can't push it into production because the web service callout is skipped in testing and I can't get to the 75% code coverage. I found the WebServiceMock code example in the Salesforce documentation but I have no idea how to modify the code so that it tests my class specifically.

Here is the generic WebServiceMock code:

@isTest
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) {
       docSample.EchoStringResponse_element respElement = 
           new docSample.EchoStringResponse_element();
       respElement.EchoStringResult = 'Mock response';
       response.put('response_x', respElement);
    }
}

Webservice callout class:

public class WebSvcCallout {
    public static String callEchoString(String input) {
        docSample.DocSamplePort sample = new docSample.DocSamplePort();
        sample.endpoint_x = 'http://api.salesforce.com/foo/bar';

        // This invokes the EchoString method in the generated class
        String echo = sample.EchoString(input);

        return echo;
    }
}

Webservice callout test:

@isTest
private class WebSvcCalloutTest {
    @isTest static void testEchoString() {              
        // 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);
    }
}

I would appreciate any ideas! Thanks! Kim

  • A link the the referenced Salesforce documentation would be helpful. Thanks. – eyedar May 13 '14 at 19:28
4

All that the mock is is a class written as part of your tests that pretends to be the web service. Its input is the Wsdl2Apex ("Generate from WSDL" button) generated (or hand written) request classes and its output is the response classes. Instead of the Salesforce framework serializing, transmitting, receiving and deserializing, your mock can just look at (or ignore) the input objects and create (using "new") and set values in the response objects.

Calling Test.setMock in your test just wires in your mock to be used for any web service calls that follow, allowing more of your code to get covered.

If the code to call the real service was generated by Wsdl2Apex, then examine the code near the call to WebServiceCallout.invoke in that generated code. Think of your mock as a more or less a replacement for that WebServiceCallout.invoke in terms of the request objects that will come in and the response objects you should generate. Then the other factor to build in is what you know about how the web service actually works: return typical values.

If the web service does the same thing all the time then you are done. If there are several different request and response patterns then your mock will have to be made a bit more complicated and generate responses depending on the request objects. But best to start simple...

  • Thanks! I think I have narrowed down the code I'm having an issue with and what the original code is doing. In essence, the original code is pulling a list of ContactIDs (but in general only one at a time) and adding the PDF it created to that contact record. I tried hard-coding a ContactID into the test class, but something is wrong. Any thoughts! respElement.addpdfresult=contactids('003L000000IEg3p'); – Kim Mar 12 '14 at 0:26
  • 2
    @Kim Tests normally should not contain hard coded ids and instead should create their own objects. (Tests normally don't and shouldn't see objects already in the org.) So at the start of your test method just create and insert a Contact and after the insert get the id and use that: if it goes out in the request pick it up and pass it back in the response; or otherwise pass it to your mock e.g. in the constructor. – Keith C Mar 12 '14 at 0:45

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.