mockito
mockito copied to clipboard
Mocks created with GenerateMocks do not throw on missing stub when the function returns a Future<void>
A call on a function with the signature Future<void> returnsFutureVoid() => Future.value();
with no expected calls set up with when
will not cause a MissingStubError.
I have read through the README, the FAQ and some of the test cases. From what I understand, this error should always be thrown for mocks generated with GenerateMocks
. I couldn't find any documented problems with functions that return a future. I was not able to reproduce the issue for the mock in the mockito_test.dart
file.
I'll open a pull request with a new test case to demonstrate the issue. If this is a valid bug, I would appreciate any advice on how to fix it.
I've just noticed that this also happens if the function returns void
, and there are existing tests that expect no MissingStubError
:
test('a method which returns Future<void> can be called without stubbing',
() {
expect(() => foo.returnsFutureVoid(), returnsNormally);
});
test('a method which returns Future<void>? can be called without stubbing',
() {
expect(() => foo.returnsNullableFutureVoid(), returnsNormally);
});
If this really the correct behaviour then I think there is a bug in the documentation here:
https://github.com/dart-lang/mockito/blob/094d07cdceca1f9f4ef863fb57045295298e8682/NULL_SAFETY_README.md?plain=1#L147
When a mock class generated with
@GenerateNiceMocks
receives a method call which does not match any method stub created with thewhen
API, a simple, legal default value is returned. This is the default and recommended "missing stub" behavior.
There is a "classic" "missing stub" behavior, which is to throw an exception when such a method call is received. To generate a mock class with this behavior, use
@GenerateMocks
:
This makes it sound like the call should throw, because the test never used when
.
Yes it is intentional for functions that return both void
and Future<void>
and we should document that.
What's the rationale behind this behaviour? That void
and Future<void>
can only ever return one kind of value, so the missing mock doesn't matter? (Not the case for Future<void>?
, also they all can throw...)
Yeah that's the general idea. We're implementing the idea that it's a pain to make people spell out in tests, "when this void-returning method is called with whatever, it should return, big surprise, nothing." You're right that there are multiple behaviors such a call could do, like throw anything. 🤷 It's just an implementation choice.
I think it would be more consistent to make function that return void
throw, just like functions returning any other type. However this seems like a breaking change, since there could be tests relying on the current behaviour.
I spotted this problem when the code I was testing was calling a function returning Future<void>
with the wrong arguments. This caused the stub set up with when
to not run, making the test to fail in a weird way due to the side effect of the stub not getting executed. I managed to work around the issue by calling verify
with the same arguments used to set up when
. This throws straight away, and fail the test with a good error message.