Java – Mocking static methods

javamockingstatic methodstdd

Having recently returned from a Test Driven Development (TDD) course I had the following thought.

While writing unit tests using Mockito we came up against of the problem of mocking static methods. It was suggested by one developer we use PowerMock, which allows mocking of static methods, and then we got into a big discussion on how we should approach this problem.

However, in my experience static methods should only really be used as utility type methods. The classic example in java being Math.random().

So a static method should only, execute one defined action regardless of any interaction with a class instance. If this is not the case, and you require class instance interaction, your method should not be static and you need to rethink your design.

So my question is, with this in mind should you need to mock static methods at all? If they are always performing a simple action, then surely you should just call them as you would in real code.

Best Answer

Generally speaking, @KonradMorawski's answer is good and complete. However, I would like to add that there is one scenario that I would consider it valuable to mock static methods - the static factory method.

Personally, in my code I very infrequently use static factory methods; I only use them if the created object is stateless, the factory is stateless, and the created object has no dependencies - and even then I'm still not very likely most of the time. Otherwise, I use an instance of a factory object, which can then be mocked.

The issue with using a static factory method as provided is that the created objects will not be mocks or spys, which means you will not be able to call verify on them, and you will not control access to these objects in advance. For example consider a math application like the following:

public abstract class ComplexNumber {
    private double realPart;
    private double imaginaryPart;
    ComplexNumber(double realPart, double imaginaryPart) {
        this.realPart = realPart;
        this.imaginaryPart = imaginaryPart;
    }
    public static ComplexNumber create(double realPart, double imaginaryPart) {
        return new ComplexNumber(realPart, imaginaryPart);
    }
}

public class RootCalculator {
    // Whatever is appropriate
    public List<ComplexNumber> roots(double... coefficients) {
        // somewhere in the code
        ComplexNumber number = new ComplexNumber(something, somethingElse);
        // blah blah
    }
}

public class RootCalculatorTest {
     @Test
     public testCalculator() {
         RootCalculator calc = new RootCalculator();
         List<ComplexNumber> roots = calc.roots(1, 0, 1); // equivalent to x^2 + 1 = 0
         for(ComplexNumber number : roots) {
             // verify(...);
         }
     }
}

Note that you can't call verify on the returned complex numbers, nor can you verify that the factory method itself was called the correct number of times. With PowerMock you can do both. Note that using PowerMock here is superior to just calling new ComplexNumber().

Of course the best way to do it is just inject an instance of a factory, which can then be mocked, avoiding PowerMock and allowing you to do all the normal testing behavior.