This article is a guide on how to mock callback functions and verify that the callback functions are called in Dart/Flutter unit tests.
The article is divided into:
1. Introduction
Let's say we have a function readDate
with the definition below:
void readData(void Function() onDataReadComplete) {
print('Reading data');
onDataReadComplete();
}
The function takes a callback onDataReadComplete
as a lone positional parameter and it calls onDataReadComplete
after it prints ('Reading data').
Our task here is to write a unit test to confirm that onDataReadComplete
is run whenever readData
runs.
In order to do this we need to mock onDataReadComplete
and confirm that it is actually called.
2. Mocking The Callback
In other to mock the callback, we will use the mock library mockito.
The first step is to add the mockito
dependecy to our project by including it in the pubspec.yaml
file. We will also add the test library to the pubspec.yaml
file.
dev_dependencies:
mockito:
test:
Mockito has two ways to generate mock objects:
For this article, we will use the manual mock implementation for simplicity.
A class can be mocked manually by creating a class that extends Mock and implements the class to be mocked.
Below is a sample from the documentation:
class MockHttpServer extends Mock implements HttpServer {}
This means we need a class to represent our function so our mock class can implement it.
We will make use of Dart's Callable Classes.
To allow an instance of your Dart class to be called like a function, implement the call() method.
This means we can represent our void Function() onDataReadComplete
function as this below:
abstract class OnDataReadComplete {
void call();
}
The class is an abstract
class since we won't be providing an implementation of the call
method
.
The call
method must have the same definition as the function to be mocked. This is why it is a void
method.
Now, we can create our mock class like this below:
class MockOnDataReadComplete extends Mock implements OnDataReadComplete {}
We can now, use MockOnDataReadComplete
in our test.
3. Testing The Callback
We will follow the following steps in testing the callback function:
- Create the mock object
mockOnDataReadComplete
usingMockOnDataReadComplete
. - Run the
readData
function withmockOnDataReadComplete
passed as a parameter. - Use the
verify
function to confirm thatmockOnDataReadComplete()
is called once. Note that you need to call the function like thismockOnDataReadComplete()
and not just pass the variablemockOnDataReadComplete
to the verify function
test('onDataReadComplete gets called whenever readData runs', () {
//Creates the mock object
final mockOnDataReadComplete = MockOnDataReadComplete();
//Runs the function
readData(mockOnDataReadComplete);
//Confirm that the mock object is called
verify(mockOnDataReadComplete()).called(1);
});
Here is the full test file:
import 'package:mockito/mockito.dart';
import 'package:test/test.dart';
void readData(void Function() onDataReadComplete) {
print('Reading data');
onDataReadComplete();
}
abstract class OnDataReadComplete {
void call();
}
class MockOnDataReadComplete extends Mock implements OnDataReadComplete {}
void main() {
test('onDataReadComplete gets called whenever readData runs', () {
//Creates the mock object
final mockOnDataReadComplete = MockOnDataReadComplete();
//Runs the function
readData(mockOnDataReadComplete);
//Confirm that the mock object is called
verify(mockOnDataReadComplete()).called(1);
});
}
And now we run our tests and it passes!
The complete project can be found on Github.