5

I'm trying to avoid using PowerMockito here. We have legacy code which contains methods that are both static and void and there are tests which need to mock them. Is there a way to do it or is refactoring legacy code the only way here?

class MySample {
       public static void sampleMethod(String argument){
                //do something
       }
}

If I use the general MockStatic syntax, it asks me to return something:

MockedStatic <MySample> sampleMock = Mockito.mockStatic( MySample.class );
sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)));

Exception:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at com.mytests.Test.setMock(Test.java:35)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, which is not supported
 3. you are stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed

Edit: Please note that I'm looking to mock a method that is BOTH static and void.

Kumar
  • 1,023
  • 1
  • 10
  • 23
  • 1
    Does this answer your question? [How to mock static method without powermock](https://stackoverflow.com/questions/44967108/how-to-mock-static-method-without-powermock) – chand mohd Sep 10 '20 at 17:04
  • Thanks for answering, but the example cited is not for a void method. – Kumar Sep 10 '20 at 17:33
  • @Slaw The accepted answer in that question expects us to have an instance, but here the method to test is static. Is there an example for a method that is both static and void? – Kumar Sep 11 '20 at 04:35

2 Answers2

4

What do you want to happen when the mocked method gets called?

The default behavior is that nothing happens. By calling sampleMock.when(), you indicated that you wanted to change from the default behavior to something else. Mockito is complaining because you didn't then follow that up with a call to then___() to specify what should happen instead.

There are a few different things I can think of that you might want to have happen:

1. Do nothing

As previously stated, this is the default behavior, so if this is all you want, you can just remove the second line and it should work. But, if you really need to have a when call (e.g. for argument capture), you can instead finish off the line with an empty thenAnswer:

sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
    .thenAnswer(invocation -> null);

2. Call the real method

sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
    .thenCallRealMethod();

3. Do something else

sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
    .thenAnswer(invocation -> {
        // insert code to do something else here
        return null;
    });

4. Throw an exception

sampleMock.when(() -> MySample.sampleMethod(Mockito.any(String.class)))
    .thenThrow(RuntimeException.class);

Update

As previously mentioned, the default behavior is to do nothing, but I learned it's also possible to specify an alternate default behavior by providing an Answer when creating the mock. For example, to have the default behavior call the real method instead:

MockedStatic <MySample> sampleMock = Mockito.mockStatic( MySample.class, Mockito.CALLS_REAL_METHODS );

But beware - as noted by Marc in this answer, the real method will still be called even if you override the default behavior! This may be fixed in the future; see Marc's answer for some good references

Kevin K
  • 9,344
  • 3
  • 37
  • 62
  • Thanks you for answering @Kevin K, could you perhaps take a look at this question: https://stackoverflow.com/q/63840898/1668384 – Kumar Sep 11 '20 at 05:10
  • 1
    @Kumar I learned that it's possible to change the default mock behavior and updated the answer here to inform about that. I think that should answer your other question too; if you can figure the default behavior to call the real method, then you can add `when`/`then` rules for just the specific methods you want to mock. – Kevin K Sep 11 '20 at 05:20
  • 2
    @KevinK your update is correct but the default behavior `.callRealMethod()` will always trigger the static methods even if stubbed. More details on my answer https://stackoverflow.com/a/63841319/8484783 – Marc Sep 11 '20 at 10:09
  • Thanks @Marc, that's good to know. Also I didn't know about `Mockito.CALLS_REAL_METHODS`, that's useful, going to update my sample for that – Kevin K Sep 18 '20 at 04:54
0

Adding @RunWith(PowerMockRunner.class) to your class header will prevent the throw of the aforementioned exception type!

Ikbel
  • 1,817
  • 1
  • 17
  • 30