Mockito (since version 2) detects stubbings that are not used, which is a very good thing generally.
Now consider the following code:
result = foo(1) || foo(2); // generally: true if any input is true
and the stubbings:
when(foo(1)).return(true);
when(foo(2)).return(false);
Now foo(2)
is unnecessarily stubbed. However, the slightest refactoring on the original code may change that (changing the expression to foo(2) || foo(1)
). In this case, I’d like to leave the stubbing in to check that the result is true
if any input is true
. (Assume that short-cutting is not necessary, but possible, and of course the real code is a lot more involved).
Now my question: What’s the elegant way to do that? Preferable for a single stubbing? Using MockitoJUnitRunner.Silent
as the runner suppresses the warning for the whole test class.
A late answer to this question:
To put it shortly, Mockito.lenient()
can be used to bypass the exception particularly for that stub, instead of applying MockitoJUnitRunner.Silent
for the whole test class.
The API was only introduced (almost a year) after this question was raised, unfortunately.
Mockito.lenient().when(foo(2)).return(false);
But I would also suggest simplifying the testing approach so that the exception would not even appear.
Let's say your function to be tested is like this:
public boolean bar() {
boolean result = foo(1) || foo(2);
return result;
}
Whether foo(1)
or foo(2)
returns true/false is not a concern in testing bar()
, instead the combinations of different scenarios is what to be tested, simply like this:
result = a || b;
a | b | bar() should return |
---|---|---|
true | true | true |
true | false | true |
false | true | true |
false | false | false |
Due to the short circuit behaviour or the OR operation, it boils down to at most 3 test cases (if you really want to) by combining the first 2 cases:
bar()
should return true when a
is truebar()
should return true when a
is false and b
is truebar()
should return false when a
is false and b
is falseImplementing these 3 test cases won't give you the unnecessary stubbing exception.
Now foo(2) is unnecessarily stubbed. However, the slightest refactoring on the original code may change that (changing the expression to foo(2) || foo(1)). In this case, I’d like to leave the stubbing in to check that the result is true if any input is true. (Assume that short-cutting is not necessary, but possible, and of course the real code is a lot more involved).
While any refactoring occurs on the bar()
function (e.g. result = b || a
), it is unavoidable to refactor the test cases at the same time to reflect the new logic, especially the short circuit effect given by OR operation is really leading to different behaviour of bar()
.
If short circuiting is not expected in the logic, and it is indeed implemented so that it is won't have short circuiting while the logic runs, then Mockito will not raise such exception, since both stubs of foo(1)
and foo(2)
will be really needed.
What I want to say is that Mockito is raising the exception correctly solely based on the implementation, it is suggested to either design the test cases to reflect the short-circuited logic, or to apply a workaround with Mockito.lenient()
What’s the elegant way to do that? Preferable for a single stubbing?
I think that stubbing two distinct invocations while you expect to have a single one of them to be invoked doesn't provide a meaningful unit test.
As I read that :
when(foo(1)).return(true);
when(foo(2)).return(true);
I expect to see something like that in the code :
result = foo(1) && foo(2);
not : result = foo(1) || foo(2);
In your case, I would have two distinct invocations to the tested method (in one or two tests according to the readability of it) and for each one, I would mock only the expected foo()
invocation, not both.
Using MockitoJUnitRunner.Silent as the runner suppresses the warning for the whole test class.
Personally, I don't like the idea to hide warnings while you may improve the test code quality.
About MockitoJUnitRunner.Silent, you can read that (emphasis is mine) :
Using this implementation of the runner is not recommended. Engineers should care for removing unused stubbings because they are dead code, they add unnecessary details, potentially making the test code harder to comprehend. If you have good reasons to use the silent runner, let us know at the mailing list or raise an issue in our issue tracker. See also UnnecessaryStubbingException
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With