Is it possible to throw an exception whenever a mock is called with non-predefined arguments? There is Answers.RETURNS_SMART_NULLS
, but it's not really what I need, since it doesn't work if null
is legitimate return value, which doesn't lead to NullPointerException
, but rather to errors later on.
Edit: some background. So, in Mockito when you define a mock, you specify the return values for each call like this:
when(myMock.someMethod(arg1, arg2)).thenReturn(returnValue);
When myMock.someMethod
is called with arguments, for which I didn't give a return value in the test, it just returns null
. I would like to configure it to crash right away and tell me that I forgot to define the return value for some combination of parameters.
Edit 2: There were suggestions to provide a custom defaultAnswer
that would throw exceptions when called. Unfortunately, this doesn't work. The default answers' answer()
method is called even if a mock is present. Here's a sample:
public class Test { public static class Adder { public int add(int a, int b) { return a + b; } } public static final Answer<Object> THROW_ON_UNDEFINED_ARGS = new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { throw new IllegalArgumentException( String.format("Calling a mock with undefined arguments: %s %s", invocation.getMethod(), Arrays.toString(invocation.getArguments()))); } }; public static void main(String[] args) { Adder adderMock = mock(Adder.class, THROW_ON_UNDEFINED_ARGS); when(adderMock.add(2, 3)).thenReturn(5); System.out.println(adderMock.add(2, 3)); } }
The exception is thrown even though adderMock.add(2, 3)
is defined.
You could provide a default Answer
in the construction of your mock that always throws an exception. Then every call that is stubbed will act like usual. Everything outside those paths will throw an exception. Something like this:
final String arg = "some arg"; Collection<Object> object = mock(Collection.class, new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { throw new IllegalArgumentException("You cannot invoke " + invocation.getMethod() + " with " + Arrays.toString(invocation.getArguments())); } }); doReturn(true).when(object).add(arg); object.add(arg); // Goes ok object.add("azertyuiop"); // Throws the exception
First, a bit of "good engineering" mumble - why would you like to do this? Mockito tries to 'promote' BDD style - you set up (mock) your calls, you execute the code and verify interactions were exactly as you expected rather then 'it didn't called anything else' - Do you try to do something described in Finding irrelevant invocation? Generally if I want to mock all the cases, but one - this makes my ask myself whether my tests are really OK.
Anyway, to the topic :)
In Mockito, you can define multiple when
s with different values, like
class Foo { public String bar(int a) { return "bar = " + a; } } Mockito.when(task.bar(Matchers.anyInt())).thenReturn("L") Mockito.when(task.bar(3)).thenThrow(new IllegalAccessError()) task.bar(4); // returns "L" task.bar(3); //throws IllegalAccessError
Notice that the order of when
s DOES matter. The rules are processed in reversed order (or rather overrides the actual matchers). In my code we first mock for anyInt, then for 3 - which works. If you reverse it - both calls to bar()
will return 'L'.
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