Mockito: how to mock a static method with parameters and void return type without of invocation of real method?

Viewed 476

In other words:

How to use "doAnswer" stubbing for static mocks in mockito?

I didn't find a way to do it. I found only the "when(...).then(...)" way to stub static methods.

For Example:

I want to linearize method SwingUtilities.invokeLater (Why? I want it simple :-)).

Using the latest Mockito I can mock static methods and write somthing like this (in try-with-resource block of course):

Answer<Object> directInvocationAnswer = invocation -> {
    ((Runnable) invocation.getArgument(0)).run();
    return null;
};
MockedStatic<SwingUtilities> mockedStatic = Mockito.mockStatic(SwingUtilities.class, CALLS_REAL_METHODS);
mockedStatic.when(() -> SwingUtilities.invokeLater(any(Runnable.class))).then(directInvocationAnswer);

It works, but I can see a NPE in the event queue. It doesn't work. At all.

It is understandable, because () -> SwingUtilities.invokeLater(any(Runnable.class)) invokes real SwingUtilities.invokeLater with null as parameter (any() returns null) and mockito can't stop the real invocation, because it does not known (at this point in time) - is is a "normal" invocation in production code or a stubbing invocation.

And I can't remove CALLS_REAL_METHODS, because I want to use other methods of the class.

Yes, I can trick mockito and avoid calling of SwingUtilities.invokeLater(null):

Answer<Object> directInvocationAnswer = invocation -> {
    ((Runnable) invocation.getArgument(0)).run();
    return null;
};
MockedStatic<SwingUtilities> mockedStatic = Mockito.mockStatic(SwingUtilities.class, CALLS_REAL_METHODS);
any(Runnable.class); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
mockedStatic.when(() ->
       SwingUtilities.invokeLater(MyUtils::nop)) // <<<<<<<<<<<<<<<<<<<<<<
   .then(directInvocationAnswer);
return mockedStatic;

It works here, but it's very ugly und it does not work in all cases - the real method was invoked at least once.

Are there any ways to use doAnswer-like stubbing for static mocks in mockito?

1 Answers

I would not mock SwingUtilities at all. A general rule for mocking is "don't mock what don't own". I would wrap the calls to SwingUtilities into a separate class with non-static methods and inject an instance of that class. Then you can easily mock the wrapper class without the static-mock crutch.

Related