|
| 1 | +--- |
| 2 | +title: Transition of platform channel test interfaces to flutter_test package |
| 3 | +description: The setMockMessageHandler method related APIs have moved from package:flutter to package:flutter_test |
| 4 | +--- |
| 5 | + |
| 6 | +## Summary |
| 7 | + |
| 8 | +The following methods have been replaced by APIs in the `flutter_test` package: `BinaryMessenger.checkMessageHandler`, `BinaryMessenger.setMockMessageHandler`, `BinaryMessenger.checkMockMessageHandler`, `BasicMessageChannel.setMockMessageHandler`, `MethodChannel.checkMethodCallHandler`, `MethodChannel.setMockMethodCallHandler`, and `MethodChannel.checkMockMethodCallHandler`. The `onPlatformMessage` callback is no longer used by the Flutter framework. |
| 9 | + |
| 10 | +## Context |
| 11 | + |
| 12 | +As part of a refactoring of the low-level plugin communications architecture, we have moved from the previous `onPlatformMessage`/`handlePlatformMessage` logic to a per-channel buffering system implemented in the engine in the `ChannelBuffers` class. To maintain compatibility with existing code, the existing `BinaryMessenger.setMessageHandler` API has been refactored to use the new `ChannelBuffers` API. |
| 13 | + |
| 14 | +One difference between the `ChannelBuffers` API and the previous API is that the new API is more consistent in its approach to asynchrony. As a side-effect, the APIs around message passing are now entirely asynchronous. |
| 15 | + |
| 16 | +This posed a problem for the implementation of the legacy testing APIs which, for historical reasons, were previously in the `flutter` package. Since they relied on the underlying logic being partly synchronous, they required refactoring. To avoid adding even more test logic into the `flutter` package, a decision was made to move this logic to the `flutter_test` package. |
| 17 | + |
| 18 | +## Description of change |
| 19 | + |
| 20 | +Specifically, the following APIs were affected: |
| 21 | + |
| 22 | +* `BinaryMessenger.checkMessageHandler`: Obsolete. |
| 23 | +* `BinaryMessenger.setMockMessageHandler`: Replaced by `TestDefaultBinaryMessenger.setMockMessageHandler`. |
| 24 | +* `BinaryMessenger.checkMockMessageHandler`: Replaced by `TestDefaultBinaryMessenger.checkMockMessageHandler`. |
| 25 | +* `BasicMessageChannel.setMockMessageHandler`: Replaced by `TestDefaultBinaryMessenger.setMockDecodedMessageHandler`. |
| 26 | +* `MethodChannel.checkMethodCallHandler`: Obsolete. |
| 27 | +* `MethodChannel.setMockMethodCallHandler`: Replaced by `TestDefaultBinaryMessenger.setMockMethodCallHandler`. |
| 28 | +* `MethodChannel.checkMockMethodCallHandler`: Replaced by `TestDefaultBinaryMessenger.checkMockMessageHandler`. |
| 29 | + |
| 30 | +These replacements are only available to code using the new `TestDefaultBinaryMessengerBinding` (such as any code using `testWidgets` in a `flutter_test` test). There is no replacement for production code that was using these APIs, as they were not intended for production code use. |
| 31 | + |
| 32 | +Tests using `checkMessageHandler` have no equivalent in the new API, since message handler registration is handled directly by the `ChannelBuffers` object, which does not expose the currently registered listener for a channel. (Tests verifying handler registration appear to be rare.) |
| 33 | + |
| 34 | +Code that needs migrating may see errors such as the following: |
| 35 | + |
| 36 | +``` |
| 37 | + error - The method 'setMockMessageHandler' isn't defined for the type 'BinaryMessenger' at test/sensors_test.dart:64:8 - (undefined_method) |
| 38 | +
|
| 39 | + error • The method 'setMockMethodCallHandler' isn't defined for the type 'MethodChannel' • test/widgets/editable_text_test.dart:5623:30 • undefined_method |
| 40 | +
|
| 41 | +[error] The method 'setMockMessageHandler' isn't defined for the type 'BasicMessageChannel' (test/material/feedback_test.dart:37:36) |
| 42 | +``` |
| 43 | + |
| 44 | +In addition, the `onPlatformMessage` callback, which previously was hooked by the framework to receive messages from plugins, is no longer used (and will be removed in due course). As a result, calling this callback to inject messages into the framework no longer has an effect. |
| 45 | + |
| 46 | +## Migration guide |
| 47 | + |
| 48 | +The `flutter_test` package provides some shims so that uses of the obsolete `setMock...` and `checkMock...` methods will continue to work. Tests that previously did not import `package:flutter_test/flutter_test.dart` can do so to enable these shims; this should be sufficient to migrate most code. |
| 49 | + |
| 50 | +These shim APIs are deprecated, however. Instead, in code using `WidgetTester` (e.g. using `testWidgets`), it is recommended to use the following patterns to replace calls to those methods (where `tester` is the `WidgetTester` instance): |
| 51 | + |
| 52 | +<!-- skip --> |
| 53 | +```dart |
| 54 | +// old code |
| 55 | +ServicesBinding.defaultBinaryMessenger.setMockMessageHandler(...); |
| 56 | +ServicesBinding.defaultBinaryMessenger.checkMockMessageHandler(...); |
| 57 | +// new code |
| 58 | +tester.binding.defaultBinaryMessenger.setMockMessageHandler(...); |
| 59 | +tester.binding.defaultBinaryMessenger.checkMockMessageHandler(...); |
| 60 | +``` |
| 61 | + |
| 62 | +<!-- skip --> |
| 63 | +```dart |
| 64 | +// old code |
| 65 | +myChannel.setMockMessageHandler(...); |
| 66 | +myChannel.checkMockMessageHandler(...); |
| 67 | +// new code |
| 68 | +tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler(myChannel, ...); |
| 69 | +tester.binding.defaultBinaryMessenger.checkMockMessageHandler(myChannel, ...); |
| 70 | +``` |
| 71 | + |
| 72 | +<!-- skip --> |
| 73 | +```dart |
| 74 | +// old code |
| 75 | +myMethodChannel.setMockMethodCallHandler(...); |
| 76 | +myMethodChannel.checkMockMethodCallHandler(...); |
| 77 | +// new code |
| 78 | +tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(myMethodChannel, ...); |
| 79 | +tester.binding.defaultBinaryMessenger.checkMockMessageHandler(myMethodChannel, ...); |
| 80 | +``` |
| 81 | + |
| 82 | +Tests that use `package:test` and `test()` can be changed to use `package:flutter_test` and `testWidgets()` to get access to a `WidgetTester`. |
| 83 | + |
| 84 | +Code that does not have access to a `WidgetTester` can refer to `TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger` instead of `tester.binding.defaultBinaryMessenger`. |
| 85 | + |
| 86 | +Tests that do not use the default test widgets binding (`AutomatedTestWidgetsFlutterBinding`, which is initialized by `testWidgets`) can mix the `TestDefaultBinaryMessengerBinding` mixin into their binding to get the same results. |
| 87 | + |
| 88 | +Tests that manipulate `onPlatformMessage` will no longer function as designed. To send mock messages to the framework, consider using `ChannelBuffers.push`. There is no mechanism to intercept messages from the plugins and forward them to the framework in the new API. If your use case requires such a mechanism, please file a bug. |
| 89 | + |
| 90 | +## Timeline |
| 91 | + |
| 92 | +Landed in version: 2.3.0-17.0.pre.1<br> |
| 93 | +In stable release: not yet |
| 94 | + |
| 95 | +## References |
| 96 | + |
| 97 | +{% include master-api.md %} |
| 98 | + |
| 99 | +API documentation: |
| 100 | +* [`TestDefaultBinaryMessenger`][] |
| 101 | +* [`TestDefaultBinaryMessengerBinding`][] |
| 102 | + |
| 103 | +Relevant PRs: |
| 104 | +* [PR #76288: Migrate to ChannelBuffers.push][] |
| 105 | + |
| 106 | +<!-- Master channel link: --> |
| 107 | +[`TestDefaultBinaryMessenger`]: https://master-api.flutter.dev/flutter/[link_to_relevant_page].html |
| 108 | +[`TestDefaultBinaryMessengerBinding`]: https://master-api.flutter.dev/flutter/[link_to_relevant_page].html |
| 109 | + |
| 110 | +[PR #76288: Migrate to ChannelBuffers.push]: {{site.github}}/flutter/flutter/pull/76288] |
0 commit comments