How to fix Null issue when using Mockito's `any` or `captureAny`
This morning I was trying to verify an invocation with Mockito in Dart, but somehow it threw an error about Null.
The argument type 'Null' can't be assigned to the parameter type 'Todo'. dart(argument_type_not_assignable)

A few searches proposed unsatisfactory workarounds, basically saying we should change our API to accept a nullable parameter:
- https://stackoverflow.com/questions/66582801/after-migrating-flutter-code-to-null-safety-mock-objects-not-accepting-any
- https://stackoverflow.com/questions/71230978/the-argument-type-null-cant-be-assigned-to-the-parameter-type-int-flutter
The official Mockito doc about null safety isn't particularly useful either: https://github.com/dart-lang/mockito/blob/master/NULL_SAFETY_README.md#argument-matchers
Eventually, I found this:
- https://github.com/dart-lang/mockito/issues/630#issuecomment-1631680087
- https://stackoverflow.com/a/74223774
What they mean is that you may implement a Mock that supports nullable types, without changing your actual API. What's more, @GenerateNiceMocks already does that for us.
So in my test, instead of defining my mockTodoProvider as a TodoProvider, I defined it as a MockTodoProvider, and now my test compiles!
Before:
main() {
late TodoProvider todoProvider;
setUp(() async {
todoProvider = MockTodoProvider();
});
testWidgets(...);
}After:
main() {
late MockTodoProvider todoProvider;
setUp(() async {
todoProvider = MockTodoProvider();
});
testWidgets(...);
}Now my test compiles and runs fine:
testWidgets('delete todo', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(...));
...
// Check the box.
await tester.tap(find.byType(Checkbox));
// Verify that update() has been called.
final verificationResult = verify(p.update(captureAny));
// Check that the passed Todo has been marked as done.
final capturedTodo = verificationResult.captured.first;
expect(capturedTodo.done, isTrue);
});Related docs: