Mockito mock static method

289 views Asked by At

I need to test the method myMethod in the class MyClass and in order to do so I need to intercept the nextInt call to make return a specified value. How do I do so?

import static org.apache.commons.lang3.RandomUtils;

public class MyClass {
    public int myMethod() {
        int a = nextInt();
        return a;
    }
}

This is what I tried and I'd like a solutiona in this way with mockito or powerMock.

import org.apache.commons.lang3.RandomUtils;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import tech.delvi.recipeBusinessLogic.MyClass;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;

public class Prova {
    public static void main(String[] args) {
        test();
    }

    public static void test() {
        MockedStatic<RandomUtils> randomUtilsMockedStatic = Mockito.mockStatic(RandomUtils.class);
        randomUtilsMockedStatic.when(() -> RandomUtils.nextInt()).thenReturn(1);

        MyClass myClass = mock(MyClass.class);
        assertEquals(1, myClass.myMethod());
    }
}
1

There are 1 answers

1
Matteo NNZ On

Generally speaking (not all the time), the need of mocking static methods flags a bad design in the code.

If your code uses a static method, it means it needs exactly that method to be used no matter the usage. If however you need to mock it for tests, then maybe you don't really need a static method but an interface that returns something different depending on the context.

Sometimes, we simply don't have the choice (e.g. we don't control the code we're testing, and that code is using a static method that we need to mock) so in that case, using a mocking library to mock it is the only option left. But if the code is yours (which I think is the case), then I would design it in a way that you can mock it more easily. For example:

public class MyClass {

    private final Supplier<Integer> intSupplier;

    public MyClass(Supplier<Integer> intSupplier) {
        this.intSupplier = intSupplier;
    }

    public int myMethod() {
        int a = intSupplier.get();
        return a;
    }
}

Like that, in production you will do:

MyClass myClass = new MyClass(() -> nextInt());

... and in the tests, you can do:

MyClass myClass = new MyClass(() -> 1);