Flutter MethodCallHandler Test with Mockito
MethodChannel
can be used to establish a connection between platform-specific APIs and Dart code. Today, let me introduce how to use Mockito
to test a MethodCallHandler
implementation which is called from the platform side.
MethodChannel
MethodChannel
is used to call platform-specific APIs from Dart code and vice versa. This is the technology commonly used to build a package or plugin that requires access to the APIs.
The details could be found in the official document.
Listener Callback
As an example, we will implement listener callbacks that are triggered from the platform side though MethodChannel
.
SampleBridge
Let's create the SampleBridge class that communicates with platforms through MethodChannel
. The basic requirement is to have MethodCallHandler
to trigger a specific listener callback based on the signal from the platform.
Environment
- Dart: 2.13.1
- Flutter: 2.2.1
HelloListener.dart
HelloListener
is the listener class that receives callbacks from the platform side. We have two functions to be called when the platform calls MethodCallHandler
: helloFromTheOtherSide
and goodBye
.
SampleBridge.dart
SampleBridge
is the main module which receives calls from the platform through MethodChannel
and trigger the designated callback of HelloListener
. Set handleMethodCall
to MethodCallHander
upon setting a HelloListener
instance to its static variable.
On a side note, though we are extracting call.arguments
in the same function, arguments evaluation and handling should be delegated to another module for easier and cleaner unit testing.
SampleBridge Use Case
Testing
Now, let's use Mockito
to test if the right callback of HelloListener gets triggered as expected.
Adjustment for the Null Safe Dart Versions
Since Dart supported null safe, there have been changes in how to create mocks with Mockito
. A simple example would be that you can no longer pass any
in the arguments when setting the stub return value on functions like this: when(MockInstance.functionStub(any)).thenReturn("Stub Value!")
.
You can read more about it on their GitHub page.
As a solution, we have to use a module called build_runner
. Before writing test cases, we will generate mock classes with this module so we can use them on the tests. Install the required modules by adding mockito
and build_runner
to dev_dependencies
.
pubspec.yaml
method_call_handler_test.dart - for build_runner
As I mentioned earlier, pass HelloListener to the annotation “@GenerateMocks
” in order to generate a HelloListener mock. By the way, you can pass multiple classes of which you would like to generate mocks since the function takes an array.
Now, run the command below to let build_runner
do the job.
$ flutter pub run build_runner build
The next step is to start writing test cases importing method_call_handler_test.mocks.dart, which was created by the previous command.
method_call_handler_test.dart - with mocks
We are going to test if helloFromTheOtherSide
and goodBye
are called with expected arguments, and throw an error when a String argument wasn't passed. Since we are using MethodChannel, first we have to call TestWidgetsFlutterBinding.ensureInitialized()
. Otherwise, an error “Null check operator used on a null value” will be raised.
Test Execution Command
$ flutter test -r expanded test/method_call_handler_test.dart
The option -r
is to specify the level of the report: compact
(default), expanded
, or json
Result
00:00 +0: HelloListener helloFromTheOtherSide with a String argument, it should trigger onHelloFromOtherSide with the String value00:00 +1: HelloListener helloFromTheOtherSide with no arguments passed, it should trigger onHelloFromOtherSide with correct args00:00 +2: HelloListener goodBye with a String argument, it should trigger the onGoodBye with correct args00:00 +3: HelloListener goodBye with no arguments passed, it should trigger onHelloFromOtherSide with correct args00:00 +4: All tests passed!
Here, we successfully validated that the respective listener callbacks get triggered by the platform through MethodChannel
.
TL;DR
You can use mockito
and build_runner
to test your MethodCallHandler implementation.