Search code examples
javamockitojunit5

Mockito a void method


How do I write a mockito test for the below method? IntReqDecorate.decorate adds an Id to a call.

public class IntVisitor implements Visitor {

    private final IntReqDecorator intReqDecorator;

    public InternalCallVisitor() {
        this.intReqDecorator = new IntReqDecorator();
    }

    @Override
    public void apply(Call call) {
        intReqDecorator.decorate(call);
    }
}

Solution

  • You're in a bit of a bind here. Your IntVisitor class is very tightly coupled to the concrete class IntReqDecorator. And the apply method is defined, verbatim, to do the same thing as intReqDecorator.decorate. So without changing any of the signatures, the best you can possibly do is write the same test you did for decorate but over again.

    Now, what you probably should do with this code is break that dependency. First, your constructor concretely builds an IntReqDecorator the moment it's constructed. You can still do that as a handy default, but you should provide a way for the caller to specify the decorator they wish to use. We can do that by overloading the constructor.

    public InternalCallVisitor() {
      this(new IntReqDecorator());
    }
    
    public InternalCallVisitor(IntReqDecorator intReqDecorator) {
      this.intReqDecorator = intReqDecorator;
    }
    

    Now this alone is enough firepower for us to write a good test. We can mock IntReqDecorator and use the one-argument constructor in tests.

    But I would go even further. You only ever use one method from IntReqDecorator, namely decorate. But since it's a concrete class, it probably has other methods that we don't really need here. So in an effort to follow dependency inversion, it may be a good idea to create an interface IntReqDecoratorLike (choose a better name for your use case) that has just that one method, and then have IntReqDecorator implement that interface.

    Then your constructor takes a IntReqDecoratorLike that is capable of doing only exactly what we need it to. The great thing about this is that you barely even have to mock anything to test it. You could theoretically just write a new (ordinary) class that implements IntReqDecoratorLike and use that in tests. We'll probably still use the mocking framework, since it does provide good error messages and built-in validation, but the alternative is there in principle.

    As a very broad general rule, when you find yourself scratching your head and saying "This code looks difficult to test", you should take a step back. Because oftentimes, you can make a change to the API that not only makes testing easier but also makes the code more ergonomic to use down the road.