0

Context

I have a delegate class which is a sort of "dispatcher", with one only public generic entry point (processRequest) and a set of private methods to compose the answer:

public class MyDelegateImpl implements MyDelegate {
    @Override
    public MyResponse processRequest(MyInput request)
    {
        //logic to determine a dispatch through the private methods
        switch (methodToUse)
        {
            case 1:
                 return method1();
            case 2:
                 return method2();
            etc.
        }
    }
    private MyResponse method1() {...}
    private MyResponse method2() {...}
    etc.
}

I am testing all the behaviors of this class using the framework JUnit. One of the private methods of this class contains a call to a public and not static method of an utility class called SOAPPricingHandler, which performs SOAP calls to an external service:

private MyResponse methodN()
{
    //...stuff
    SOAPPricingHandler myHandler = new SOAPPricingHandler();
    Document soapResponse = myHandler.getSoapAnswer();
    //...other stuff
    return someResponse;
}

For information, this is the basic structure of SOAPPricingHandler:

public class SOAPPricingHandler {
    public SOAPPricingHandler()
    {
         //some constructions
    }

    public Document getSoapAnswer()
    {
        //soap call, some reworking and then
        return mySoapAnswerAsDocument;
    }
}

Also, consider that MyDelegateImpl is called in delegation, meaning that there is a generic class MyProxySession which will create a future task and delegate the execution of its processRequest method to the implementation of MyDelegate.

Question

In order to unit test this behavior, I need to mock this part of code inside the private MyResponse methodN() and not actually perform a SOAP request to the external service:

SOAPPricingHandler myHandler = new SOAPPricingHandler();
Document soapResponse = myHandler.getSoapAnswer();

However, I don't really understand how (and if) I can do it. I have tried the following:

@Test
public void myUnitTest()
{
    ...
    SOAPPricingHandler soapRequestEngine = new SOAPPricingHandler(); 
    SOAPPricingHandler spySoapRequestEngine = Mockito.spy(soapRequestEngine);
    Mockito.when(spySoapRequestEngine.getSoapAnswer()).thenReturn(xmlExpectedAnswer);
    MyResponse response = session.processRequest(someInput); //<-- the SOAPPricingHandler method will be called in here.
}

... but of course it doesn't work, because I'm not using the spied session of SOAPPricingHandler inside the processRequest (which is creating a new instance).

The same happens if I use this:

Mockito.doReturn(xmlExpectedAnswer).when(spySoapRequestEngine).getSoapAnswer();

Can anyone lead me through the proper design of this unit test? If you see some wrong design in the private MyResponse methodN() which could be designed differently in order to have a better testability, I'm open to proposals as well. Thanks in advance.

Matteo NNZ
  • 11,930
  • 12
  • 52
  • 89
  • Use dependency injection. `MyDelegateImpl`'s constructor should receive a `SOAPPricingHandler`. Then you can pass in a mock/fake/stub/whatever. – Michael Feb 21 '19 at 10:53
  • @Michael I had thought about that, but the interface `MyDelegate` should remain as is as it's contacted by multiple services and they only know about a construction without parameters. – Matteo NNZ Feb 21 '19 at 10:55
  • The interface isn't changing. The constructor of one concrete implementation is. If some classes are *assuming* that all implementations of `MyDelegate` will have a no-arg constructor, then that's a bad assumption to make, leading to an overall bad design, leading to the problem you are currently having. – Michael Feb 21 '19 at 10:55
  • @Michael thanks for your help. I agree that the overall design might be bad, but I'm working with legacy code and I can't really change it. The interface that contacts `MyDelegate` sends a generic input and cannot contain an "if the request looks like we need a SOAP Handler then let's use a different constructor". It's inside `MyDelegateImpl` method `processRequest` that I can actually decide which method to use, unfortunately. – Matteo NNZ Feb 21 '19 at 11:13
  • As for the question you marked as duplicate, it is still assuming that the `SOAPPricingHandler` is injected or there would be no connection betweehn the method I want to stub and the spied object which is calling it. So I agree 100% with you when you say that the legacy implementation is bad (that's why my question says "if" and not only "how" can I do), but my question is not _really_ a duplicate of the one you flagged :) – Matteo NNZ Feb 21 '19 at 11:15
  • "I can't really change it" Then its untestable. SOAPPricingHandler could trivially be made into a static method, which would then by mockable via PowerMock. There is no compelling reason *not* to make that change. – Michael Feb 21 '19 at 11:21
  • @Michael, thats something I can do, and probably one answer I was looking for to the part of my question “if you see any better design of the method I’m open to proposals”. If you don’t mind reopen the question, that would allow you or someone else to post the answer. But if you really think it should stay as a duplicate I don’t mind, you finally gave me the tip I was looking for so thanks for that :) – Matteo NNZ Feb 21 '19 at 11:26
  • You're right that that probably wasn't the best duplicate but I was certain that this had been asked before. I've pointed to a different question which I think matches a lot closer. Anyway, glad you're on the right track. – Michael Feb 21 '19 at 11:34
  • @Michael, in fact this duplicate now really looks what I’m looking for. Thanks a lot for your help! – Matteo NNZ Feb 21 '19 at 11:44

0 Answers0