5

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.

1
  • 4
    Math.random() is actually a very poor API IMO. It hides the stateful nature of random number generation and will just lead programmers to do the wrong thing. Pure functions like Math.sqrt are fine. Mar 11, 2016 at 19:08

5 Answers 5

3

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.

1
  • 1
    The complex number is a ValueObject, normally VO are never mocked (its like mocking a string or Integer). Mar 7, 2014 at 13:59
1

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.

Yes, if the code is properly written. Sometimes it isn't, and you still need to test it. Refactoring can be very time-consuming (statics are typically associated with high coupling and other no-nos), so this is kind of a workaround.

Refactoring could be not only unfeasible, but impossible. The static method might be out of your reach - what if your code has to call a static method from a third party library, and it's not stateless, takes a long time to execute, has special requirements (database, web access)... In order to test your code you need to mock this method.

1

Mock static methods is a bad idea, i use only if i'm testing legacy code and i can't refactor for whatever reason. But in a normal development TDD cycle its a bad smell.

I always remembers one phrase from Ian Cooper "test things you want to preserve", when you are mocking a static you are stating in our test that do you want to preserve not the functionality, you want to preserve this design with a static method call. Are you sure you want to preserve this?

0

I agree with durron597 but with one exception. I discovered this question as I was reviewing some of my code where I need to inject a mock factory rather than a mock object since the mock object I was injecting may need to change within the code under test. This caused me to analyze another section of code where I realized that what I have another case where it feels like I should be using a static factory method. As durron597 says above:

"if the created object is stateless, the factory is stateless, and the created object has no dependencies"

However, the part I have a problem with is "the created object has no dependencies". Isn't that the point of mocking an object? I want to remove or replace dependencies as well as the values that might be returned from a "real" implementation.

In my case, I just want my static factory method to return this mock and I'm good to go, just as I was when only one instance was needed that I was injecting via a protected constructor. So, it makes me sad to think that I either have to use PowerMock or abandon a perfectly legitimate and elegant use of a language construct to the creation an instance of something which essentially has methods which are static in spirit. And yes, as I eluded to earlier, I discovered I was doing exactly the latter when I discovered the new need for another factory elsewhere. So, I started modifying this case first to use a static factory method when I discovered Mockito can't mock a static.

Moreover, caving to the "create an instance" approach just to do my unit tests means that I have a layer that has knowledge of something it doesn't need to know about. If my factory is simple enough to not require parameters or initialization by this or a higher level, I'd love to avoid the coupling that this approach requires and use the static factory method only at the level where it's needed. In this case, the layer above doesn't need to know much less care about whether there's a factory involved or not!

So, in summary, yes static CAN be a smell indicator but, as with all language constructs, IMHO there is a proper time and place for them all, that's why they're there, right? :)

0

In my experience you can reasonably mock static methods when: * the static methods is slow and using it can hinder the performances of the unit tests at the point developers stop running the tests. * the static method comes from a 3rd party library you cannot modify and maybe it requires complex dependecies that again can slow down the test execution. * if you are really interested in the interaction with the static method more that in the result itselfl.

For instance, you're developing a class that acts as a cache around a very time-expensive static method. What you want to test is probably

  • that the first time the cache is called, the same parameters are provided to the expensive static method.
  • that the second time the cache is called with a set of params already used, you have a cache hit and the static method is not called at all.

This is just a basic example to make you understand my idea.

I must admit that I usually try not to have the need to mock static methods in test if I'm able to.

Your Answer

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