Migrate to ChannelBuffers.push (#82564)

diff --git a/dev/automated_tests/flutter_test/ticker_test.dart b/dev/automated_tests/flutter_test/ticker_test.dart
index 48d53f5..6881468 100644
--- a/dev/automated_tests/flutter_test/ticker_test.dart
+++ b/dev/automated_tests/flutter_test/ticker_test.dart
@@ -11,6 +11,6 @@
     Ticker((Duration duration) { }).start();
 
     final ByteData? message = const StringCodec().encodeMessage('AppLifecycleState.paused');
-    await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) {});
+    await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) {});
   });
 }
diff --git a/dev/integration_tests/web_e2e_tests/test_driver/text_editing_integration.dart b/dev/integration_tests/web_e2e_tests/test_driver/text_editing_integration.dart
index 3f3e149..b1cc580 100644
--- a/dev/integration_tests/web_e2e_tests/test_driver/text_editing_integration.dart
+++ b/dev/integration_tests/web_e2e_tests/test_driver/text_editing_integration.dart
@@ -29,9 +29,6 @@
     app.main();
     await tester.pumpAndSettle();
 
-    // TODO(nurhan): https://github.com/flutter/flutter/issues/51885
-    SystemChannels.textInput.setMockMethodCallHandler(null);
-
     // Focus on a TextFormField.
     final Finder finder = find.byKey(const Key('input'));
     expect(finder, findsOneWidget);
@@ -56,9 +53,6 @@
     app.main();
     await tester.pumpAndSettle();
 
-    // TODO(nurhan): https://github.com/flutter/flutter/issues/51885
-    SystemChannels.textInput.setMockMethodCallHandler(null);
-
     // Focus on a TextFormField.
     final Finder finder = find.byKey(const Key('empty-input'));
     expect(finder, findsOneWidget);
@@ -83,9 +77,6 @@
     app.main();
     await tester.pumpAndSettle();
 
-    // TODO(nurhan): https://github.com/flutter/flutter/issues/51885
-    SystemChannels.textInput.setMockMethodCallHandler(null);
-
     // This text will show no-enter initially. It will have 'enter-pressed'
     // after `onFieldSubmitted` of TextField is triggered.
     final Finder textFinder = find.byKey(const Key('text'));
@@ -118,9 +109,6 @@
     app.main();
     await tester.pumpAndSettle();
 
-    // TODO(nurhan): https://github.com/flutter/flutter/issues/51885
-    SystemChannels.textInput.setMockMethodCallHandler(null);
-
     // Focus on a TextFormField.
     final Finder finder = find.byKey(const Key('input'));
     expect(finder, findsOneWidget);
@@ -152,9 +140,6 @@
     app.main();
     await tester.pumpAndSettle();
 
-    // TODO(nurhan): https://github.com/flutter/flutter/issues/51885
-    SystemChannels.textInput.setMockMethodCallHandler(null);
-
     // Focus on a TextFormField.
     final Finder finder = find.byKey(const Key('input'));
     expect(finder, findsOneWidget);
@@ -203,9 +188,6 @@
     app.main();
     await tester.pumpAndSettle();
 
-    // TODO(nurhan): https://github.com/flutter/flutter/issues/51885
-    SystemChannels.textInput.setMockMethodCallHandler(null);
-
     // Select something from the selectable text.
     final Finder finder = find.byKey(const Key('selectable'));
     expect(finder, findsOneWidget);
diff --git a/examples/hello_world/test_driver/smoke_web_engine_test.dart b/examples/hello_world/test_driver/smoke_web_engine_test.dart
index a909d63..a74e993 100644
--- a/examples/hello_world/test_driver/smoke_web_engine_test.dart
+++ b/examples/hello_world/test_driver/smoke_web_engine_test.dart
@@ -5,7 +5,7 @@
 import 'dart:async';
 
 import 'package:flutter_driver/flutter_driver.dart';
-import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
+import 'package:test/test.dart';
 import 'package:webdriver/async_io.dart';
 
 // TODO(web): Migrate this test to a normal integration_test with a WidgetTester.
@@ -35,6 +35,7 @@
     test('enable accessibility', () async {
       await driver.setSemantics(true);
 
+      // TODO(ianh): this delay violates our style guide. We should instead wait for a triggering event.
       await Future<void>.delayed(const Duration(seconds: 2));
 
       // A flutter web app may be rendered directly on the body of the page, or
diff --git a/packages/flutter/lib/src/foundation/binding.dart b/packages/flutter/lib/src/foundation/binding.dart
index 97a9237..71fe7cd 100644
--- a/packages/flutter/lib/src/foundation/binding.dart
+++ b/packages/flutter/lib/src/foundation/binding.dart
@@ -104,8 +104,8 @@
   /// A number of additional bindings are defined as extensions of
   /// [BindingBase], e.g., [ServicesBinding], [RendererBinding], and
   /// [WidgetsBinding]. Each of these bindings define behaviors that interact
-  /// with a [ui.PlatformDispatcher], e.g., [ServicesBinding] registers a
-  /// [ui.PlatformDispatcher.onPlatformMessage] handler, and [RendererBinding]
+  /// with a [ui.PlatformDispatcher], e.g., [ServicesBinding] registers
+  /// listeners with the [ChannelBuffers], and [RendererBinding]
   /// registers [ui.PlatformDispatcher.onMetricsChanged],
   /// [ui.PlatformDispatcher.onTextScaleFactorChanged],
   /// [ui.PlatformDispatcher.onSemanticsEnabledChanged], and
diff --git a/packages/flutter/lib/src/services/binary_messenger.dart b/packages/flutter/lib/src/services/binary_messenger.dart
index 39ac547..1acf6f5 100644
--- a/packages/flutter/lib/src/services/binary_messenger.dart
+++ b/packages/flutter/lib/src/services/binary_messenger.dart
@@ -2,12 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-
 import 'dart:typed_data';
 import 'dart:ui' as ui;
 
-import 'binding.dart';
-
 /// A function which takes a platform message and asynchronously returns an encoded response.
 typedef MessageHandler = Future<ByteData?>? Function(ByteData? message);
 
@@ -19,12 +16,39 @@
   /// const constructors so that they can be used in const expressions.
   const BinaryMessenger();
 
-  /// Calls the handler registered for the given channel.
+  /// Queues a message.
   ///
-  /// Typically called by [ServicesBinding] to handle platform messages received
-  /// from [dart:ui.PlatformDispatcher.onPlatformMessage].
+  /// The returned future completes immediately.
+  ///
+  /// This method adds the provided message to the given channel (named by the
+  /// `channel` argument) of the [ChannelBuffers] object. This simulates what
+  /// happens when a plugin on the platform thread (e.g. Kotlin or Swift code)
+  /// sends a message to the plugin package on the Dart thread.
+  ///
+  /// The `data` argument contains the message as encoded bytes. (The format
+  /// used for the message depends on the channel.)
+  ///
+  /// The `callback` argument, if non-null, is eventually invoked with the
+  /// response that would have been sent to the platform thread.
+  ///
+  /// In production code, it is more efficient to call
+  /// `ServicesBinding.instance.channelBuffers.push` directly.
+  ///
+  /// In tests, consider using
+  /// `tester.binding.defaultBinaryMessenger.handlePlatformMessage` (see
+  /// [WidgetTester], [TestWidgetsFlutterBinding], [TestDefaultBinaryMessenger],
+  /// and [TestDefaultBinaryMessenger.handlePlatformMessage] respectively).
   ///
   /// To register a handler for a given message channel, see [setMessageHandler].
+  ///
+  /// To send a message _to_ a plugin on the platform thread, see [send].
+  // TODO(ianh): deprecate this method once cocoon and other customer_tests are migrated:
+  // @NotYetDeprecated(
+  //   'Instead of calling this method, use ServicesBinding.instance.channelBuffers.push. '
+  //   'In tests, consider using tester.binding.defaultBinaryMessenger.handlePlatformMessage '
+  //   'or TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.handlePlatformMessage. '
+  //   'This feature was deprecated after v2.1.0-10.0.pre.'
+  // )
   Future<void> handlePlatformMessage(String channel, ByteData? data, ui.PlatformMessageResponseCallback? callback);
 
   /// Send a binary message to the platform plugins on the given channel.
@@ -43,37 +67,6 @@
   /// The handler's return value, if non-null, is sent as a response, unencoded.
   void setMessageHandler(String channel, MessageHandler? handler);
 
-  /// Returns true if the `handler` argument matches the `handler` previously
-  /// passed to [setMessageHandler].
-  ///
-  /// This method is useful for tests or test harnesses that want to assert the
-  /// handler for the specified channel has not been altered by a previous test.
-  ///
-  /// Passing null for the `handler` returns true if the handler for the
-  /// `channel` is not set.
-  bool checkMessageHandler(String channel, MessageHandler? handler);
-
-  /// Set a mock callback for intercepting messages from the [send] method on
-  /// this class, on the given channel, without decoding them.
-  ///
-  /// The given callback will replace the currently registered mock callback for
-  /// that channel, if any. To remove the mock handler, pass null as the
-  /// `handler` argument.
-  ///
-  /// The handler's return value, if non-null, is used as a response, unencoded.
-  ///
-  /// This is intended for testing. Messages intercepted in this manner are not
-  /// sent to platform plugins.
-  void setMockMessageHandler(String channel, MessageHandler? handler);
-
-  /// Returns true if the `handler` argument matches the `handler` previously
-  /// passed to [setMockMessageHandler].
-  ///
-  /// This method is useful for tests or test harnesses that want to assert the
-  /// mock handler for the specified channel has not been altered by a previous
-  /// test.
-  ///
-  /// Passing null for the `handler` returns true if the handler for the
-  /// `channel` is not set.
-  bool checkMockMessageHandler(String channel, MessageHandler? handler);
+  // Looking for setMockMessageHandler or checkMockMessageHandler?
+  // See this shim package: packages/flutter_test/lib/src/deprecated.dart
 }
diff --git a/packages/flutter/lib/src/services/binding.dart b/packages/flutter/lib/src/services/binding.dart
index a69c821..d0e6bca 100644
--- a/packages/flutter/lib/src/services/binding.dart
+++ b/packages/flutter/lib/src/services/binding.dart
@@ -30,7 +30,6 @@
     _instance = this;
     _defaultBinaryMessenger = createBinaryMessenger();
     _restorationManager = createRestorationManager();
-    window.onPlatformMessage = defaultBinaryMessenger.handlePlatformMessage;
     initLicenses();
     SystemChannels.system.setMessageHandler((dynamic message) => handleSystemMessage(message as Object));
     SystemChannels.lifecycle.setMessageHandler(_handleLifecycleMessage);
@@ -49,6 +48,28 @@
   BinaryMessenger get defaultBinaryMessenger => _defaultBinaryMessenger;
   late BinaryMessenger _defaultBinaryMessenger;
 
+  /// The low level buffering and dispatch mechanism for messages sent by
+  /// plugins on the engine side to their corresponding plugin code on
+  /// the framework side.
+  ///
+  /// This exposes the [dart:ui.channelBuffers] object. Bindings can override
+  /// this getter to intercept calls to the [ChannelBuffers] mechanism (for
+  /// example, for tests).
+  ///
+  /// In production, direct access to this object should not be necessary.
+  /// Messages are received and dispatched by the [defaultBinaryMessenger]. This
+  /// object is primarily used to send mock messages in tests, via the
+  /// [ChannelBuffers.push] method (simulating a plugin sending a message to the
+  /// framework).
+  ///
+  /// See also:
+  ///
+  ///  * [PlatformDispatcher.sendPlatformMessage], which is used for sending
+  ///    messages to plugins from the framework (the opposite of
+  ///    [channelBuffers]).
+  ///  * [platformDispatcher], the [PlatformDispatcher] singleton.
+  ui.ChannelBuffers get channelBuffers => ui.channelBuffers;
+
   /// Creates a default [BinaryMessenger] instance that can be used for sending
   /// platform messages.
   @protected
@@ -56,7 +77,6 @@
     return const _DefaultBinaryMessenger._();
   }
 
-
   /// Called when the operating system notifies the application of a memory
   /// pressure situation.
   ///
@@ -253,17 +273,20 @@
 class _DefaultBinaryMessenger extends BinaryMessenger {
   const _DefaultBinaryMessenger._();
 
-  // Handlers for incoming messages from platform plugins.
-  // This is static so that this class can have a const constructor.
-  static final Map<String, MessageHandler> _handlers =
-      <String, MessageHandler>{};
+  @override
+  Future<void> handlePlatformMessage(
+    String channel,
+    ByteData? message,
+    ui.PlatformMessageResponseCallback? callback,
+  ) async {
+    ui.channelBuffers.push(channel, message, (ByteData? data) {
+      if (callback != null)
+        callback(data);
+    });
+  }
 
-  // Mock handlers that intercept and respond to outgoing messages.
-  // This is static so that this class can have a const constructor.
-  static final Map<String, MessageHandler> _mockHandlers =
-      <String, MessageHandler>{};
-
-  Future<ByteData?> _sendPlatformMessage(String channel, ByteData? message) {
+  @override
+  Future<ByteData?> send(String channel, ByteData? message) {
     final Completer<ByteData?> completer = Completer<ByteData?>();
     // ui.PlatformDispatcher.instance is accessed directly instead of using
     // ServicesBinding.instance.platformDispatcher because this method might be
@@ -272,6 +295,8 @@
     // ui.PlatformDispatcher.instance because the PlatformDispatcher may be
     // dependency injected elsewhere with a different instance. However, static
     // access at this location seems to be the least bad option.
+    // TODO(ianh): Use ServicesBinding.instance once we have better diagnostics
+    // on that getter.
     ui.PlatformDispatcher.instance.sendPlatformMessage(channel, message, (ByteData? reply) {
       try {
         completer.complete(reply);
@@ -288,66 +313,26 @@
   }
 
   @override
-  @pragma('vm:notify-debugger-on-exception')
-  Future<void> handlePlatformMessage(
-    String channel,
-    ByteData? data,
-    ui.PlatformMessageResponseCallback? callback,
-  ) async {
-    ByteData? response;
-    try {
-      final MessageHandler? handler = _handlers[channel];
-      if (handler != null) {
-        response = await handler(data);
-      } else {
-        ui.channelBuffers.push(channel, data, callback!);
-        callback = null;
-      }
-    } catch (exception, stack) {
-      FlutterError.reportError(FlutterErrorDetails(
-        exception: exception,
-        stack: stack,
-        library: 'services library',
-        context: ErrorDescription('during a platform message callback'),
-      ));
-    } finally {
-      if (callback != null) {
-        callback(response);
-      }
-    }
-  }
-
-  @override
-  Future<ByteData?>? send(String channel, ByteData? message) {
-    final MessageHandler? handler = _mockHandlers[channel];
-    if (handler != null)
-      return handler(message);
-    return _sendPlatformMessage(channel, message);
-  }
-
-  @override
   void setMessageHandler(String channel, MessageHandler? handler) {
     if (handler == null) {
-      _handlers.remove(channel);
+      ui.channelBuffers.clearListener(channel);
     } else {
-      _handlers[channel] = handler;
-      ui.channelBuffers.drain(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
-        await handlePlatformMessage(channel, data, callback);
+      ui.channelBuffers.setListener(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
+        ByteData? response;
+        try {
+          response = await handler(data);
+        } catch (exception, stack) {
+
+          FlutterError.reportError(FlutterErrorDetails(
+            exception: exception,
+            stack: stack,
+            library: 'services library',
+            context: ErrorDescription('during a platform message callback'),
+          ));
+        } finally {
+          callback(response);
+        }
       });
     }
   }
-
-  @override
-  bool checkMessageHandler(String channel, MessageHandler? handler) => _handlers[channel] == handler;
-
-  @override
-  void setMockMessageHandler(String channel, MessageHandler? handler) {
-    if (handler == null)
-      _mockHandlers.remove(channel);
-    else
-      _mockHandlers[channel] = handler;
-  }
-
-  @override
-  bool checkMockMessageHandler(String channel, MessageHandler? handler) => _mockHandlers[channel] == handler;
 }
diff --git a/packages/flutter/lib/src/services/message_codec.dart b/packages/flutter/lib/src/services/message_codec.dart
index c312972..ba99134 100644
--- a/packages/flutter/lib/src/services/message_codec.dart
+++ b/packages/flutter/lib/src/services/message_codec.dart
@@ -95,7 +95,6 @@
   ByteData encodeErrorEnvelope({ required String code, String? message, Object? details});
 }
 
-
 /// Thrown to indicate that a platform interaction failed in the platform
 /// plugin.
 ///
diff --git a/packages/flutter/lib/src/services/platform_channel.dart b/packages/flutter/lib/src/services/platform_channel.dart
index 397384d..3be96aa 100644
--- a/packages/flutter/lib/src/services/platform_channel.dart
+++ b/packages/flutter/lib/src/services/platform_channel.dart
@@ -75,31 +75,10 @@
     }
   }
 
-  /// Sets a mock callback for intercepting messages sent on this channel.
-  /// Messages may be null.
-  ///
-  /// The given callback will replace the currently registered mock callback for
-  /// this channel, if any. To remove the mock handler, pass null as the
-  /// `handler` argument.
-  ///
-  /// The handler's return value is used as a message reply. It may be null.
-  ///
-  /// This is intended for testing. Messages intercepted in this manner are not
-  /// sent to platform plugins.
-  void setMockMessageHandler(Future<T> Function(T? message)? handler) {
-    if (handler == null) {
-      binaryMessenger.setMockMessageHandler(name, null);
-    } else {
-      binaryMessenger.setMockMessageHandler(name, (ByteData? message) async {
-        return codec.encodeMessage(await handler(codec.decodeMessage(message)));
-      });
-    }
-  }
+  // Looking for setMockMessageHandler?
+  // See this shim package: packages/flutter_test/lib/src/deprecated.dart
 }
 
-Expando<Object> _methodChannelHandlers = Expando<Object>();
-Expando<Object> _methodChannelMockHandlers = Expando<Object>();
-
 /// A named channel for communicating with platform plugins using asynchronous
 /// method calls.
 ///
@@ -393,7 +372,6 @@
   /// similarly to what happens if no method call handler has been set.
   /// Any other exception results in an error envelope being sent.
   void setMethodCallHandler(Future<dynamic> Function(MethodCall call)? handler) {
-    _methodChannelHandlers[this] = handler;
     binaryMessenger.setMessageHandler(
       name,
       handler == null
@@ -402,53 +380,7 @@
     );
   }
 
-  /// Returns true if the `handler` argument matches the `handler` previously
-  /// passed to [setMethodCallHandler].
-  ///
-  /// This method is useful for tests or test harnesses that want to assert the
-  /// handler for the specified channel has not been altered by a previous test.
-  ///
-  /// Passing null for the `handler` returns true if the handler for the channel
-  /// is not set.
-  bool checkMethodCallHandler(Future<dynamic> Function(MethodCall call)? handler) => _methodChannelHandlers[this] == handler;
-
-  /// Sets a mock callback for intercepting method invocations on this channel.
-  ///
-  /// The given callback will replace the currently registered mock callback for
-  /// this channel, if any. To remove the mock handler, pass null as the
-  /// `handler` argument.
-  ///
-  /// Later calls to [invokeMethod] will result in a successful result,
-  /// a [PlatformException] or a [MissingPluginException], determined by how
-  /// the future returned by the mock callback completes. The [codec] of this
-  /// channel is used to encode and decode values and errors.
-  ///
-  /// This is intended for testing. Method calls intercepted in this manner are
-  /// not sent to platform plugins.
-  ///
-  /// The provided `handler` must return a `Future` that completes with the
-  /// return value of the call. The value will be encoded using
-  /// [MethodCodec.encodeSuccessEnvelope], to act as if platform plugin had
-  /// returned that value.
-  void setMockMethodCallHandler(Future<dynamic>? Function(MethodCall call)? handler) {
-    _methodChannelMockHandlers[this] = handler;
-    binaryMessenger.setMockMessageHandler(
-      name,
-      handler == null ? null : (ByteData? message) => _handleAsMethodCall(message, handler),
-    );
-  }
-
-  /// Returns true if the `handler` argument matches the `handler` previously
-  /// passed to [setMockMethodCallHandler].
-  ///
-  /// This method is useful for tests or test harnesses that want to assert the
-  /// handler for the specified channel has not been altered by a previous test.
-  ///
-  /// Passing null for the `handler` returns true if the handler for the channel
-  /// is not set.
-  bool checkMockMethodCallHandler(Future<dynamic> Function(MethodCall call)? handler) => _methodChannelMockHandlers[this] == handler;
-
-  Future<ByteData?> _handleAsMethodCall(ByteData? message, Future<dynamic>? Function(MethodCall call) handler) async {
+  Future<ByteData?> _handleAsMethodCall(ByteData? message, Future<dynamic> Function(MethodCall call) handler) async {
     final MethodCall call = codec.decodeMethodCall(message);
     try {
       return codec.encodeSuccessEnvelope(await handler(call));
@@ -464,6 +396,9 @@
       return codec.encodeErrorEnvelope(code: 'error', message: e.toString(), details: null);
     }
   }
+
+  // Looking for setMockMethodCallHandler or checkMethodCallHandler?
+  // See this shim package: packages/flutter_test/lib/src/deprecated.dart
 }
 
 /// A [MethodChannel] that ignores missing platform plugins.
diff --git a/packages/flutter/lib/src/services/restoration.dart b/packages/flutter/lib/src/services/restoration.dart
index fd00fd4..c8d4d88 100644
--- a/packages/flutter/lib/src/services/restoration.dart
+++ b/packages/flutter/lib/src/services/restoration.dart
@@ -166,7 +166,6 @@
   /// that communications channel, or to set it up differently, as necessary.
   @protected
   void initChannels() {
-    assert(!SystemChannels.restoration.checkMethodCallHandler(_methodHandler));
     SystemChannels.restoration.setMethodCallHandler(_methodHandler);
   }
 
diff --git a/packages/flutter/lib/src/services/system_channels.dart b/packages/flutter/lib/src/services/system_channels.dart
index 61fcb88..473f03a 100644
--- a/packages/flutter/lib/src/services/system_channels.dart
+++ b/packages/flutter/lib/src/services/system_channels.dart
@@ -129,6 +129,11 @@
   /// they apply, so that stale messages referencing past transactions can be
   /// ignored.
   ///
+  /// In debug builds, messages sent with a client ID of -1 are always accepted.
+  /// This allows tests to smuggle messages without having to mock the engine's
+  /// text handling (for example, allowing the engine to still handle the text
+  /// input messages in an integration test).
+  ///
   /// The methods described below are wrapped in a more convenient form by the
   /// [TextInput] and [TextInputConnection] class.
   ///
@@ -161,9 +166,15 @@
   /// is a transaction identifier. Calls for stale transactions should be ignored.
   ///
   ///  * `TextInputClient.updateEditingState`: The user has changed the contents
-  ///    of the text control. The second argument is a [String] containing a
-  ///    JSON-encoded object with seven keys, in the form expected by
-  ///    [TextEditingValue.fromJSON].
+  ///    of the text control. The second argument is an object with seven keys,
+  ///    in the form expected by [TextEditingValue.fromJSON].
+  ///
+  ///  * `TextInputClient.updateEditingStateWithTag`: One or more text controls
+  ///    were autofilled by the platform's autofill service. The first argument
+  ///    (the client ID) is ignored, the second argument is a map of tags to
+  ///    objects in the form expected by [TextEditingValue.fromJSON]. See
+  ///    [AutofillScope.getAutofillClient] for details on the interpretation of
+  ///    the tag.
   ///
   ///  * `TextInputClient.performAction`: The user has triggered an action. The
   ///    second argument is a [String] consisting of the stringification of one
@@ -174,7 +185,8 @@
   ///    one. The framework should call `TextInput.setClient` and
   ///    `TextInput.setEditingState` again with its most recent information. If
   ///    there is no existing state on the framework side, the call should
-  ///    fizzle.
+  ///    fizzle. (This call is made without a client ID; indeed, without any
+  ///    arguments at all.)
   ///
   ///  * `TextInputClient.onConnectionClosed`: The text input connection closed
   ///    on the platform side. For example the application is moved to
diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart
index bac572f..0e0c637 100644
--- a/packages/flutter/lib/src/services/text_input.dart
+++ b/packages/flutter/lib/src/services/text_input.dart
@@ -1327,9 +1327,11 @@
 
     final List<dynamic> args = methodCall.arguments as List<dynamic>;
 
+    // The updateEditingStateWithTag request (autofill) can come up even to a
+    // text field that doesn't have a connection.
     if (method == 'TextInputClient.updateEditingStateWithTag') {
+      assert(_currentConnection!._client != null);
       final TextInputClient client = _currentConnection!._client;
-      assert(client != null);
       final AutofillScope? scope = client.currentAutofillScope;
       final Map<String, dynamic> editingValue = args[1] as Map<String, dynamic>;
       for (final String tag in editingValue.keys) {
@@ -1343,9 +1345,22 @@
     }
 
     final int client = args[0] as int;
-    // The incoming message was for a different client.
-    if (client != _currentConnection!._id)
-      return;
+    if (client != _currentConnection!._id) {
+      // If the client IDs don't match, the incoming message was for a different
+      // client.
+      bool debugAllowAnyway = false;
+      assert(() {
+        // In debug builds we allow "-1" as a magical client ID that ignores
+        // this verification step so that tests can always get through, even
+        // when they are not mocking the engine side of text input.
+        if (client == -1)
+          debugAllowAnyway = true;
+        return true;
+      }());
+      if (!debugAllowAnyway)
+        return;
+    }
+
     switch (method) {
       case 'TextInputClient.updateEditingState':
         _currentConnection!._client.updateEditingValue(TextEditingValue.fromJSON(args[1] as Map<String, dynamic>));
@@ -1502,7 +1517,7 @@
     assert(shouldSave != null);
     TextInput._instance._channel.invokeMethod<void>(
       'TextInput.finishAutofillContext',
-      shouldSave ,
+      shouldSave,
     );
   }
 }
diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart
index 739d510..473f097 100644
--- a/packages/flutter/lib/src/widgets/editable_text.dart
+++ b/packages/flutter/lib/src/widgets/editable_text.dart
@@ -2112,7 +2112,7 @@
     if (_hasFocus) {
       _openInputConnection();
     } else {
-      widget.focusNode.requestFocus();
+      widget.focusNode.requestFocus(); // This eventually calls _openInputConnection also, see _handleFocusChanged.
     }
   }
 
@@ -2360,11 +2360,13 @@
 
   void _cursorWaitForStart(Timer timer) {
     assert(_kCursorBlinkHalfPeriod > _fadeDuration);
+    assert(!EditableText.debugDeterministicCursor);
     _cursorTimer?.cancel();
     _cursorTimer = Timer.periodic(_kCursorBlinkHalfPeriod, _cursorTick);
   }
 
   void _startCursorTimer() {
+    assert(_cursorTimer == null);
     _targetCursorVisibility = true;
     _cursorBlinkOpacityController.value = 1.0;
     if (EditableText.debugDeterministicCursor)
diff --git a/packages/flutter/test/cupertino/picker_test.dart b/packages/flutter/test/cupertino/picker_test.dart
index 1515262..f56df59 100644
--- a/packages/flutter/test/cupertino/picker_test.dart
+++ b/packages/flutter/test/cupertino/picker_test.dart
@@ -201,7 +201,7 @@
         final List<int> selectedItems = <int>[];
         final List<MethodCall> systemCalls = <MethodCall>[];
 
-        SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+        tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
           systemCalls.add(methodCall);
         });
 
@@ -254,7 +254,7 @@
         final List<int> selectedItems = <int>[];
         final List<MethodCall> systemCalls = <MethodCall>[];
 
-        SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+        tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
           systemCalls.add(methodCall);
         });
 
diff --git a/packages/flutter/test/cupertino/refresh_test.dart b/packages/flutter/test/cupertino/refresh_test.dart
index e01e24c..02b41cc 100644
--- a/packages/flutter/test/cupertino/refresh_test.dart
+++ b/packages/flutter/test/cupertino/refresh_test.dart
@@ -175,7 +175,7 @@
     testWidgets('drag past threshold triggers refresh task', (WidgetTester tester) async {
       final List<MethodCall> platformCallLog = <MethodCall>[];
 
-      SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+      tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
         platformCallLog.add(methodCall);
       });
 
diff --git a/packages/flutter/test/cupertino/scrollbar_test.dart b/packages/flutter/test/cupertino/scrollbar_test.dart
index 8977e2a..ba14bae 100644
--- a/packages/flutter/test/cupertino/scrollbar_test.dart
+++ b/packages/flutter/test/cupertino/scrollbar_test.dart
@@ -132,9 +132,9 @@
     await tester.pump();
 
     int hapticFeedbackCalls = 0;
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       if (methodCall.method == 'HapticFeedback.vibrate') {
-        hapticFeedbackCalls++;
+        hapticFeedbackCalls += 1;
       }
     });
 
@@ -692,9 +692,9 @@
     await tester.pump();
 
     int hapticFeedbackCalls = 0;
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       if (methodCall.method == 'HapticFeedback.vibrate') {
-        hapticFeedbackCalls++;
+        hapticFeedbackCalls += 1;
       }
     });
 
diff --git a/packages/flutter/test/cupertino/switch_test.dart b/packages/flutter/test/cupertino/switch_test.dart
index 9c475b4..6cd48bf 100644
--- a/packages/flutter/test/cupertino/switch_test.dart
+++ b/packages/flutter/test/cupertino/switch_test.dart
@@ -47,7 +47,7 @@
 
     final List<MethodCall> log = <MethodCall>[];
 
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -87,7 +87,7 @@
     bool value2 = false;
     final List<MethodCall> log = <MethodCall>[];
 
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -154,7 +154,7 @@
     bool value = false;
     final List<MethodCall> log = <MethodCall>[];
 
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -192,7 +192,7 @@
     bool value = false;
 
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart
index 86da35a..ca6edb2 100644
--- a/packages/flutter/test/cupertino/text_field_test.dart
+++ b/packages/flutter/test/cupertino/text_field_test.dart
@@ -162,7 +162,7 @@
 void main() {
   TestWidgetsFlutterBinding.ensureInitialized();
   final MockClipboard mockClipboard = MockClipboard();
-  SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
+  TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
 
   // Returns the first RenderEditable.
   RenderEditable findRenderEditable(WidgetTester tester) {
@@ -3228,7 +3228,7 @@
 
   testWidgets('text field respects keyboardAppearance from theme', (WidgetTester tester) async {
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -3251,7 +3251,7 @@
 
   testWidgets('text field can override keyboardAppearance from theme', (WidgetTester tester) async {
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
diff --git a/packages/flutter/test/cupertino/text_selection_test.dart b/packages/flutter/test/cupertino/text_selection_test.dart
index 551342f..9fc33fd 100644
--- a/packages/flutter/test/cupertino/text_selection_test.dart
+++ b/packages/flutter/test/cupertino/text_selection_test.dart
@@ -66,7 +66,7 @@
 void main() {
   TestWidgetsFlutterBinding.ensureInitialized();
   final MockClipboard mockClipboard = MockClipboard();
-  SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
+  TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
 
   // Returns true iff the button is visually enabled.
   bool appearsEnabled(WidgetTester tester, String text) {
diff --git a/packages/flutter/test/foundation/service_extensions_test.dart b/packages/flutter/test/foundation/service_extensions_test.dart
index dd7ae1a..a36f5bc 100644
--- a/packages/flutter/test/foundation/service_extensions_test.dart
+++ b/packages/flutter/test/foundation/service_extensions_test.dart
@@ -21,7 +21,8 @@
        PaintingBinding,
        SemanticsBinding,
        RendererBinding,
-       WidgetsBinding {
+       WidgetsBinding,
+       TestDefaultBinaryMessengerBinding {
 
   final Map<String, ServiceExtensionCallback> extensions = <String, ServiceExtensionCallback>{};
 
@@ -467,7 +468,7 @@
     bool completed;
 
     completed = false;
-    ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) async {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) async {
       expect(utf8.decode(message!.buffer.asUint8List()), 'test');
       completed = true;
       return ByteData(5); // 0x0000000000
@@ -494,7 +495,7 @@
     });
     expect(data, isFalse);
     expect(completed, isTrue);
-    ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', null);
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', null);
   });
 
   test('Service extensions - exit', () async {
diff --git a/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart b/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart
index 96c1c30..0ea6d95 100644
--- a/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart
+++ b/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart
@@ -2,12 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Logically this file should be part of `gesture_binding_test.dart` but is here
-// due to conflict of `flutter_test` and `package:test`.
-// See https://github.com/dart-lang/matcher/issues/98
-// TODO(CareF): Consider combine this file back to `gesture_binding_test.dart`
-// after #98 is fixed.
-
 import 'dart:ui' as ui;
 
 import 'package:clock/clock.dart';
diff --git a/packages/flutter/test/material/checkbox_test.dart b/packages/flutter/test/material/checkbox_test.dart
index d477588..6c03f41 100644
--- a/packages/flutter/test/material/checkbox_test.dart
+++ b/packages/flutter/test/material/checkbox_test.dart
@@ -267,7 +267,7 @@
   testWidgets('has semantic events', (WidgetTester tester) async {
     dynamic semanticEvent;
     bool? checkboxValue = false;
-    SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
       semanticEvent = message;
     });
     final SemanticsTester semanticsTester = SemanticsTester(tester);
@@ -300,7 +300,7 @@
     });
     expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
 
-    SystemChannels.accessibility.setMockMessageHandler(null);
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
     semanticsTester.dispose();
   });
 
diff --git a/packages/flutter/test/material/feedback_test.dart b/packages/flutter/test/material/feedback_test.dart
index 06a016c..3f80ff8 100644
--- a/packages/flutter/test/material/feedback_test.dart
+++ b/packages/flutter/test/material/feedback_test.dart
@@ -27,14 +27,14 @@
 
     setUp(() {
       semanticEvents = <Map<String, Object>>[];
-      SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
         final Map<dynamic, dynamic> typedMessage = message as Map<dynamic, dynamic>;
         semanticEvents.add(typedMessage.cast<String, Object>());
       });
     });
 
     tearDown(() {
-      SystemChannels.accessibility.setMockMessageHandler(null);
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
     });
 
     testWidgets('forTap', (WidgetTester tester) async {
diff --git a/packages/flutter/test/material/feedback_tester.dart b/packages/flutter/test/material/feedback_tester.dart
index 5f1c469..c65d994 100644
--- a/packages/flutter/test/material/feedback_tester.dart
+++ b/packages/flutter/test/material/feedback_tester.dart
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
 
 /// Tracks how often feedback has been requested since its instantiation.
 ///
@@ -10,13 +11,7 @@
 /// cannot be used in combination with other classes that do the same.
 class FeedbackTester {
   FeedbackTester() {
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
-      if (methodCall.method == 'HapticFeedback.vibrate')
-        _hapticCount++;
-      if (methodCall.method == 'SystemSound.play' &&
-          methodCall.arguments == SystemSoundType.click.toString())
-        _clickSoundCount++;
-    });
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, _handler);
   }
 
   /// Number of times haptic feedback was requested (vibration).
@@ -27,8 +22,17 @@
   int get clickSoundCount => _clickSoundCount;
   int _clickSoundCount = 0;
 
+  Future<void> _handler(MethodCall methodCall) async {
+    if (methodCall.method == 'HapticFeedback.vibrate')
+      _hapticCount++;
+    if (methodCall.method == 'SystemSound.play' &&
+        methodCall.arguments == SystemSoundType.click.toString())
+      _clickSoundCount++;
+  }
+
   /// Stops tracking.
   void dispose() {
-    SystemChannels.platform.setMockMethodCallHandler(null);
+    assert(TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(SystemChannels.platform.name, _handler));
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
   }
 }
diff --git a/packages/flutter/test/material/input_date_picker_form_field_test.dart b/packages/flutter/test/material/input_date_picker_form_field_test.dart
index 1ffe812..2e9c376 100644
--- a/packages/flutter/test/material/input_date_picker_form_field_test.dart
+++ b/packages/flutter/test/material/input_date_picker_form_field_test.dart
@@ -241,9 +241,9 @@
 
       // Fill the clipboard so that the Paste option is available in the text
       // selection menu.
-      SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
+      tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
       await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
-      addTearDown(() => SystemChannels.platform.setMockMethodCallHandler(null));
+      addTearDown(() => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null));
 
       await tester.pumpWidget(_inputDatePickerField(autofocus: true));
       await tester.pumpAndSettle();
diff --git a/packages/flutter/test/material/radio_list_tile_test.dart b/packages/flutter/test/material/radio_list_tile_test.dart
index 07f4ced..332ee8f 100644
--- a/packages/flutter/test/material/radio_list_tile_test.dart
+++ b/packages/flutter/test/material/radio_list_tile_test.dart
@@ -537,7 +537,7 @@
     final Key key = UniqueKey();
     dynamic semanticEvent;
     int? radioValue = 2;
-    SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
       semanticEvent = message;
     });
 
@@ -568,7 +568,7 @@
     expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
 
     semantics.dispose();
-    SystemChannels.accessibility.setMockMessageHandler(null);
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
   });
 
   testWidgets('RadioListTile can autofocus unless disabled.', (WidgetTester tester) async {
diff --git a/packages/flutter/test/material/radio_test.dart b/packages/flutter/test/material/radio_test.dart
index bd8efbb..048e147 100644
--- a/packages/flutter/test/material/radio_test.dart
+++ b/packages/flutter/test/material/radio_test.dart
@@ -292,7 +292,7 @@
     final Key key = UniqueKey();
     dynamic semanticEvent;
     int? radioValue = 2;
-    SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
       semanticEvent = message;
     });
 
@@ -319,7 +319,7 @@
     expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
 
     semantics.dispose();
-    SystemChannels.accessibility.setMockMessageHandler(null);
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
   });
 
   testWidgets('Radio ink ripple is displayed correctly', (WidgetTester tester) async {
diff --git a/packages/flutter/test/material/search_test.dart b/packages/flutter/test/material/search_test.dart
index c3444bb..32c968f 100644
--- a/packages/flutter/test/material/search_test.dart
+++ b/packages/flutter/test/material/search_test.dart
@@ -32,12 +32,12 @@
   setUp(() async {
     // Fill the clipboard so that the Paste option is available in the text
     // selection menu.
-    SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
     await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
   });
 
   tearDown(() {
-    SystemChannels.platform.setMockMethodCallHandler(null);
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
   });
 
   testWidgets('Can open and close search', (WidgetTester tester) async {
diff --git a/packages/flutter/test/material/switch_test.dart b/packages/flutter/test/material/switch_test.dart
index b3d8f32..34199a7 100644
--- a/packages/flutter/test/material/switch_test.dart
+++ b/packages/flutter/test/material/switch_test.dart
@@ -577,7 +577,7 @@
   testWidgets('switch has semantic events', (WidgetTester tester) async {
     dynamic semanticEvent;
     bool value = false;
-    SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
       semanticEvent = message;
     });
     final SemanticsTester semanticsTester = SemanticsTester(tester);
@@ -615,13 +615,13 @@
     expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
 
     semanticsTester.dispose();
-    SystemChannels.accessibility.setMockMessageHandler(null);
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
   });
 
   testWidgets('switch sends semantic events from parent if fully merged', (WidgetTester tester) async {
     dynamic semanticEvent;
     bool value = false;
-    SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
       semanticEvent = message;
     });
     final SemanticsTester semanticsTester = SemanticsTester(tester);
@@ -665,7 +665,7 @@
     expect(object.debugSemantics!.getSemanticsData().hasAction(SemanticsAction.tap), true);
 
     semanticsTester.dispose();
-    SystemChannels.accessibility.setMockMessageHandler(null);
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
   });
 
   testWidgets('Switch.adaptive', (WidgetTester tester) async {
diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart
index d0925f3..c7834e2 100644
--- a/packages/flutter/test/material/text_field_test.dart
+++ b/packages/flutter/test/material/text_field_test.dart
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'dart:async';
 import 'dart:math' as math;
 import 'dart:ui' as ui show window, BoxHeightStyle, BoxWidthStyle;
 
@@ -164,14 +165,20 @@
 
   setUp(() async {
     debugResetSemanticsIdCounter();
-    SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(
+      SystemChannels.platform,
+      mockClipboard.handleMethodCall,
+    );
     // Fill the clipboard so that the Paste option is available in the text
     // selection menu.
     await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
   });
 
   tearDown(() {
-    SystemChannels.platform.setMockMethodCallHandler(null);
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(
+      SystemChannels.platform,
+      null,
+    );
   });
 
   final Key textFieldKey = UniqueKey();
@@ -339,7 +346,7 @@
 
   testWidgets('TextField has consistent size', (WidgetTester tester) async {
     final Key textFieldKey = UniqueKey();
-    late String textFieldValue;
+    String? textFieldValue;
 
     await tester.pumpWidget(
       overlay(
@@ -362,15 +369,16 @@
 
     Future<void> checkText(String testValue) async {
       return TestAsyncUtils.guard(() async {
+        expect(textFieldValue, isNull);
         await tester.enterText(find.byType(TextField), testValue);
         // Check that the onChanged event handler fired.
         expect(textFieldValue, equals(testValue));
+        textFieldValue = null;
         await skipPastScrollingAnimation(tester);
       });
     }
 
     await checkText(' ');
-
     expect(findTextFieldBox(), equals(inputBox));
     expect(inputBox.size, equals(emptyInputSize));
 
@@ -416,6 +424,8 @@
       text: 'X',
       selection: TextSelection.collapsed(offset: 1),
     ));
+    await tester.idle();
+    expect(tester.state(find.byType(EditableText)), editableText);
     await checkCursorToggle();
   });
 
@@ -4694,8 +4704,8 @@
       );
 
     String clipboardContent = '';
-    SystemChannels.platform
-      .setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger
+      .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
         if (methodCall.method == 'Clipboard.setData')
           clipboardContent = methodCall.arguments['text'] as String;
         else if (methodCall.method == 'Clipboard.getData')
@@ -4767,8 +4777,8 @@
       );
 
     String clipboardContent = '';
-    SystemChannels.platform
-      .setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger
+      .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
         if (methodCall.method == 'Clipboard.setData')
           clipboardContent = methodCall.arguments['text'] as String;
         else if (methodCall.method == 'Clipboard.getData')
@@ -4840,8 +4850,8 @@
     );
 
     const String clipboardContent = 'I love Flutter!';
-    SystemChannels.platform
-      .setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger
+      .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
         if (methodCall.method == 'Clipboard.getData')
           return <String, dynamic>{'text': clipboardContent};
         return null;
@@ -4890,8 +4900,8 @@
         maxLines: 3,
       );
     String clipboardContent = '';
-    SystemChannels.platform
-      .setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger
+      .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
         if (methodCall.method == 'Clipboard.setData')
           clipboardContent = methodCall.arguments['text'] as String;
         else if (methodCall.method == 'Clipboard.getData')
@@ -4964,8 +4974,8 @@
       obscureText: true,
     );
     String clipboardContent = '';
-    SystemChannels.platform
-      .setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger
+      .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
         if (methodCall.method == 'Clipboard.setData')
           clipboardContent = methodCall.arguments['text'] as String;
         else if (methodCall.method == 'Clipboard.getData')
@@ -9371,8 +9381,8 @@
     );
 
     bool triedToReadClipboard = false;
-    SystemChannels.platform
-      .setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger
+      .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
         if (methodCall.method == 'Clipboard.getData') {
           triedToReadClipboard = true;
         }
diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart
index fda0cf2..5ed6cf0 100644
--- a/packages/flutter/test/material/text_form_field_test.dart
+++ b/packages/flutter/test/material/text_form_field_test.dart
@@ -32,7 +32,7 @@
 void main() {
   TestWidgetsFlutterBinding.ensureInitialized();
   final MockClipboard mockClipboard = MockClipboard();
-  SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
+  TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
 
   setUp(() async {
     // Fill the clipboard so that the Paste option is available in the text
diff --git a/packages/flutter/test/material/text_selection_test.dart b/packages/flutter/test/material/text_selection_test.dart
index 831afe1..1d1c1d5 100644
--- a/packages/flutter/test/material/text_selection_test.dart
+++ b/packages/flutter/test/material/text_selection_test.dart
@@ -28,7 +28,7 @@
 void main() {
   TestWidgetsFlutterBinding.ensureInitialized();
   final MockClipboard mockClipboard = MockClipboard();
-  SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
+  TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
 
   setUp(() async {
     await Clipboard.setData(const ClipboardData(text: 'clipboard data'));
diff --git a/packages/flutter/test/material/tooltip_test.dart b/packages/flutter/test/material/tooltip_test.dart
index 09f2df3..31544eb 100644
--- a/packages/flutter/test/material/tooltip_test.dart
+++ b/packages/flutter/test/material/tooltip_test.dart
@@ -1193,7 +1193,7 @@
 
   testWidgets('has semantic events', (WidgetTester tester) async {
     final List<dynamic> semanticEvents = <dynamic>[];
-    SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
       semanticEvents.add(message);
     });
     final SemanticsTester semantics = SemanticsTester(tester);
@@ -1230,7 +1230,7 @@
       },
     ]));
     semantics.dispose();
-    SystemChannels.accessibility.setMockMessageHandler(null);
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
   });
   testWidgets('default Tooltip debugFillProperties', (WidgetTester tester) async {
     final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
diff --git a/packages/flutter/test/material/tooltip_theme_test.dart b/packages/flutter/test/material/tooltip_theme_test.dart
index e18adf1..f81d8cc 100644
--- a/packages/flutter/test/material/tooltip_theme_test.dart
+++ b/packages/flutter/test/material/tooltip_theme_test.dart
@@ -1153,7 +1153,7 @@
 
   testWidgets('has semantic events by default - ThemeData.tooltipTheme', (WidgetTester tester) async {
     final List<dynamic> semanticEvents = <dynamic>[];
-    SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
       semanticEvents.add(message);
     });
     final SemanticsTester semantics = SemanticsTester(tester);
@@ -1191,12 +1191,12 @@
       },
     ]));
     semantics.dispose();
-    SystemChannels.accessibility.setMockMessageHandler(null);
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
   });
 
   testWidgets('has semantic events by default - TooltipTheme', (WidgetTester tester) async {
     final List<dynamic> semanticEvents = <dynamic>[];
-    SystemChannels.accessibility.setMockMessageHandler((dynamic message) async {
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async {
       semanticEvents.add(message);
     });
     final SemanticsTester semantics = SemanticsTester(tester);
@@ -1236,7 +1236,7 @@
       },
     ]));
     semantics.dispose();
-    SystemChannels.accessibility.setMockMessageHandler(null);
+    tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, null);
   });
 
   testWidgets('default Tooltip debugFillProperties', (WidgetTester tester) async {
diff --git a/packages/flutter/test/rendering/first_frame_test.dart b/packages/flutter/test/rendering/first_frame_test.dart
index 6b766c9..c6fe2c7 100644
--- a/packages/flutter/test/rendering/first_frame_test.dart
+++ b/packages/flutter/test/rendering/first_frame_test.dart
@@ -12,11 +12,11 @@
 import 'package:flutter_test/flutter_test.dart';
 
 void main() {
+  final TestRenderBinding binding = TestRenderBinding();
   test('Flutter dispatches first frame event on the web only', () async {
     final Completer<void> completer = Completer<void>();
-    final TestRenderBinding binding = TestRenderBinding();
     const MethodChannel firstFrameChannel = MethodChannel('flutter/service_worker');
-    firstFrameChannel.setMockMethodCallHandler((MethodCall methodCall) async {
+    binding.defaultBinaryMessenger.setMockMethodCallHandler(firstFrameChannel, (MethodCall methodCall) async {
       completer.complete();
     });
 
@@ -27,4 +27,10 @@
   }, skip: !kIsWeb);
 }
 
-class TestRenderBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, SemanticsBinding, RendererBinding {}
+class TestRenderBinding extends BindingBase
+  with SchedulerBinding,
+       ServicesBinding,
+       GestureBinding,
+       SemanticsBinding,
+       RendererBinding,
+       TestDefaultBinaryMessengerBinding { }
diff --git a/packages/flutter/test/rendering/mouse_tracker_cursor_test.dart b/packages/flutter/test/rendering/mouse_tracker_cursor_test.dart
index 7e8423f..331b2a3 100644
--- a/packages/flutter/test/rendering/mouse_tracker_cursor_test.dart
+++ b/packages/flutter/test/rendering/mouse_tracker_cursor_test.dart
@@ -56,14 +56,14 @@
 
   setUp(() {
     _binding.postFrameCallbacks.clear();
-    SystemChannels.mouseCursor.setMockMethodCallHandler((MethodCall call) async {
+    _binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.mouseCursor, (MethodCall call) async {
       if (_methodCallHandler != null)
         return _methodCallHandler!(call);
     });
   });
 
   tearDown(() {
-    SystemChannels.mouseCursor.setMockMethodCallHandler(null);
+    _binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.mouseCursor, null);
   });
 
   test('Should work on platforms that does not support mouse cursor', () async {
diff --git a/packages/flutter/test/rendering/mouse_tracker_test_utils.dart b/packages/flutter/test/rendering/mouse_tracker_test_utils.dart
index a5bd1ed..c4c0906 100644
--- a/packages/flutter/test/rendering/mouse_tracker_test_utils.dart
+++ b/packages/flutter/test/rendering/mouse_tracker_test_utils.dart
@@ -9,6 +9,7 @@
 import 'package:flutter/rendering.dart';
 import 'package:flutter/scheduler.dart';
 import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart' show TestDefaultBinaryMessengerBinding;
 
 class _TestHitTester extends RenderBox {
   _TestHitTester(this.hitTestOverride);
@@ -24,7 +25,7 @@
 // A binding used to test MouseTracker, allowing the test to override hit test
 // searching.
 class TestMouseTrackerFlutterBinding extends BindingBase
-    with SchedulerBinding, ServicesBinding, GestureBinding, SemanticsBinding, RendererBinding {
+    with SchedulerBinding, ServicesBinding, GestureBinding, SemanticsBinding, RendererBinding, TestDefaultBinaryMessengerBinding {
   @override
   void initInstances() {
     super.initInstances();
diff --git a/packages/flutter/test/rendering/rendering_tester.dart b/packages/flutter/test/rendering/rendering_tester.dart
index b6b0dd9..65ba5ae 100644
--- a/packages/flutter/test/rendering/rendering_tester.dart
+++ b/packages/flutter/test/rendering/rendering_tester.dart
@@ -9,12 +9,12 @@
 import 'package:flutter/rendering.dart';
 import 'package:flutter/scheduler.dart';
 import 'package:flutter/services.dart';
-import 'package:flutter_test/flutter_test.dart' show EnginePhase, fail;
+import 'package:flutter_test/flutter_test.dart' show TestDefaultBinaryMessengerBinding, EnginePhase, fail;
 
 export 'package:flutter/foundation.dart' show FlutterError, FlutterErrorDetails;
-export 'package:flutter_test/flutter_test.dart' show EnginePhase;
+export 'package:flutter_test/flutter_test.dart' show TestDefaultBinaryMessengerBinding, EnginePhase;
 
-class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding {
+class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, TestDefaultBinaryMessengerBinding {
   /// Creates a binding for testing rendering library functionality.
   ///
   /// If [onErrors] is not null, it is called if [FlutterError] caught any errors
diff --git a/packages/flutter/test/semantics/semantics_service_test.dart b/packages/flutter/test/semantics/semantics_service_test.dart
index b384e0f..a7ff5e0 100644
--- a/packages/flutter/test/semantics/semantics_service_test.dart
+++ b/packages/flutter/test/semantics/semantics_service_test.dart
@@ -13,12 +13,13 @@
 
   test('Semantic announcement', () async {
     final List<Map<dynamic, dynamic>> log = <Map<dynamic, dynamic>>[];
+
     Future<dynamic> handleMessage(dynamic mockMessage) async {
       final Map<dynamic, dynamic> message = mockMessage as Map<dynamic, dynamic>;
       log.add(message);
     }
 
-    SystemChannels.accessibility.setMockMessageHandler(handleMessage);
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, handleMessage);
 
     await SemanticsService.announce('announcement 1', TextDirection.ltr);
     await SemanticsService.announce('announcement 2', TextDirection.rtl);
diff --git a/packages/flutter/test/services/autofill_test.dart b/packages/flutter/test/services/autofill_test.dart
index 428f6c7..5af15da 100644
--- a/packages/flutter/test/services/autofill_test.dart
+++ b/packages/flutter/test/services/autofill_test.dart
@@ -191,15 +191,6 @@
     incoming = handler;
   }
 
-  @override
-  bool checkMethodCallHandler(Future<void> Function(MethodCall call)? handler) => throw UnimplementedError();
-
-  @override
-  void setMockMethodCallHandler(Future<void>? Function(MethodCall call)? handler)  => throw UnimplementedError();
-
-  @override
-  bool checkMockMethodCallHandler(Future<void> Function(MethodCall call)? handler) => throw UnimplementedError();
-
   void validateOutgoingMethodCalls(List<MethodCall> calls) {
     expect(outgoingCalls.length, calls.length);
     bool hasError = false;
diff --git a/packages/flutter/test/services/binding_test.dart b/packages/flutter/test/services/binding_test.dart
index 6830810..ff92a14 100644
--- a/packages/flutter/test/services/binding_test.dart
+++ b/packages/flutter/test/services/binding_test.dart
@@ -34,7 +34,7 @@
 
 L2Paragraph3''';
 
-const String licenses = '''
+const String combinedLicenses = '''
 $license1
 --------------------------------------------------------------------------------
 $license2
@@ -42,29 +42,25 @@
 
 class TestBinding extends BindingBase with SchedulerBinding, ServicesBinding {
   @override
-  BinaryMessenger createBinaryMessenger() {
-    return super.createBinaryMessenger()
-      ..setMockMessageHandler('flutter/assets', (ByteData? message) async {
-        if (const StringCodec().decodeMessage(message) == 'NOTICES') {
-          return const StringCodec().encodeMessage(licenses);
-        }
-        return null;
-      })
-      ..setMockMessageHandler('flutter/assets', (ByteData? message) async {
-        if (const StringCodec().decodeMessage(message) == 'NOTICES.Z' && !kIsWeb) {
-          return Uint8List.fromList(gzip.encode(utf8.encode(licenses))).buffer.asByteData();
-        }
-        if (const StringCodec().decodeMessage(message) == 'NOTICES' && kIsWeb) {
-          return const StringCodec().encodeMessage(licenses);
-        }
-        return null;
-      });
+  TestDefaultBinaryMessenger get defaultBinaryMessenger => super.defaultBinaryMessenger as TestDefaultBinaryMessenger;
+
+  @override
+  TestDefaultBinaryMessenger createBinaryMessenger() {
+    return TestDefaultBinaryMessenger(super.createBinaryMessenger());
   }
 }
 
 void main() {
   test('Adds rootBundle LICENSES to LicenseRegistry', () async {
-    TestBinding(); // The test binding registers a mock handler that returns licenses for the LICENSE key
+    TestBinding().defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) async {
+      if (const StringCodec().decodeMessage(message) == 'NOTICES.Z' && !kIsWeb) {
+        return Uint8List.fromList(gzip.encode(utf8.encode(combinedLicenses))).buffer.asByteData();
+      }
+      if (const StringCodec().decodeMessage(message) == 'NOTICES' && kIsWeb) {
+        return const StringCodec().encodeMessage(combinedLicenses);
+      }
+      return null;
+    });
 
     final List<LicenseEntry> licenses = await LicenseRegistry.licenses.toList();
 
diff --git a/packages/flutter/test/services/default_binary_messenger_test.dart b/packages/flutter/test/services/default_binary_messenger_test.dart
index e6a768d..4ce14e8 100644
--- a/packages/flutter/test/services/default_binary_messenger_test.dart
+++ b/packages/flutter/test/services/default_binary_messenger_test.dart
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'dart:async';
 import 'dart:convert';
 import 'dart:typed_data';
-import 'dart:ui' as ui;
+
 import 'package:flutter/services.dart';
 import 'package:flutter_test/flutter_test.dart';
 
@@ -19,36 +20,39 @@
   }
 
   test('default binary messenger calls callback once', () async {
-    int count = 0;
+    int countInbound = 0;
+    int countOutbound = 0;
     const String channel = 'foo';
-    ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+    final ByteData bar = _makeByteData('bar');
+    final Completer<void> done = Completer<void>();
+    ServicesBinding.instance!.channelBuffers.push(
       channel,
-      _makeByteData('bar'),
+      bar,
       (ByteData? message) async {
-        count += 1;
+        expect(message, isNull);
+        countOutbound += 1;
+        done.complete();
       },
     );
-    expect(count, equals(0));
-    await ui.channelBuffers.drain(channel, (ByteData? data, ui.PlatformMessageResponseCallback callback) async {
-      callback(null);
-    });
-    expect(count, equals(1));
-  });
-
-  test('can check the handler', () {
-    Future<ByteData> handler(ByteData? call) => Future<ByteData>.value(null);
-    final BinaryMessenger messenger = ServicesBinding.instance!.defaultBinaryMessenger;
-
-    expect(messenger.checkMessageHandler('test_channel', null), true);
-    expect(messenger.checkMessageHandler('test_channel', handler), false);
-    messenger.setMessageHandler('test_channel', handler);
-    expect(messenger.checkMessageHandler('test_channel', handler), true);
-    messenger.setMessageHandler('test_channel', null);
+    expect(countInbound, equals(0));
+    expect(countOutbound, equals(0));
+    ServicesBinding.instance!.defaultBinaryMessenger.setMessageHandler(
+      channel,
+      (ByteData? message) async {
+        expect(message, bar);
+        countInbound += 1;
+      },
+    );
+    expect(countInbound, equals(0));
+    expect(countOutbound, equals(0));
+    await done.future;
+    expect(countInbound, equals(1));
+    expect(countOutbound, equals(1));
   });
 
   test('can check the mock handler', () {
     Future<ByteData> handler(ByteData? call) => Future<ByteData>.value(null);
-    final BinaryMessenger messenger = ServicesBinding.instance!.defaultBinaryMessenger;
+    final TestDefaultBinaryMessenger messenger = TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger;
 
     expect(messenger.checkMockMessageHandler('test_channel', null), true);
     expect(messenger.checkMockMessageHandler('test_channel', handler), false);
diff --git a/packages/flutter/test/services/deferred_component_test.dart b/packages/flutter/test/services/deferred_component_test.dart
index cc40b8e..6665f28 100644
--- a/packages/flutter/test/services/deferred_component_test.dart
+++ b/packages/flutter/test/services/deferred_component_test.dart
@@ -11,7 +11,7 @@
   test('installDeferredComponent test', () async {
     final List<MethodCall> log = <MethodCall>[];
 
-    SystemChannels.deferredComponent.setMockMethodCallHandler((MethodCall methodCall) async {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.deferredComponent, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -27,7 +27,7 @@
   test('uninstallDeferredComponent test', () async {
     final List<MethodCall> log = <MethodCall>[];
 
-    SystemChannels.deferredComponent.setMockMethodCallHandler((MethodCall methodCall) async {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.deferredComponent, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
diff --git a/packages/flutter/test/services/fake_platform_views.dart b/packages/flutter/test/services/fake_platform_views.dart
index 9efdce7..7695c4a 100644
--- a/packages/flutter/test/services/fake_platform_views.dart
+++ b/packages/flutter/test/services/fake_platform_views.dart
@@ -8,6 +8,7 @@
 import 'package:flutter/foundation.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter/widgets.dart';
+import 'package:flutter_test/flutter_test.dart';
 
 /// Used in internal testing.
 class FakePlatformViewController extends PlatformViewController {
@@ -122,7 +123,7 @@
 
 class FakeAndroidPlatformViewsController {
   FakeAndroidPlatformViewsController() {
-    SystemChannels.platform_views.setMockMethodCallHandler(_onMethodCall);
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform_views, _onMethodCall);
   }
 
   Iterable<FakeAndroidPlatformView> get views => _views.values;
@@ -301,7 +302,7 @@
 
 class FakeIosPlatformViewsController {
   FakeIosPlatformViewsController() {
-    SystemChannels.platform_views.setMockMethodCallHandler(_onMethodCall);
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform_views, _onMethodCall);
   }
 
   Iterable<FakeUiKitView> get views => _views.values;
@@ -396,7 +397,7 @@
 
 class FakeHtmlPlatformViewsController {
   FakeHtmlPlatformViewsController() {
-    SystemChannels.platform_views.setMockMethodCallHandler(_onMethodCall);
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform_views, _onMethodCall);
   }
 
   Iterable<FakeHtmlPlatformView> get views => _views.values;
diff --git a/packages/flutter/test/services/haptic_feedback_test.dart b/packages/flutter/test/services/haptic_feedback_test.dart
index 6234a97..fa4c67e 100644
--- a/packages/flutter/test/services/haptic_feedback_test.dart
+++ b/packages/flutter/test/services/haptic_feedback_test.dart
@@ -11,7 +11,7 @@
   test('Haptic feedback control test', () async {
     final List<MethodCall> log = <MethodCall>[];
 
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -25,7 +25,7 @@
     Future<void> callAndVerifyHapticFunction(Function hapticFunction, String platformMethodArgument) async {
       final List<MethodCall> log = <MethodCall>[];
 
-      SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
         log.add(methodCall);
       });
 
diff --git a/packages/flutter/test/services/platform_channel_test.dart b/packages/flutter/test/services/platform_channel_test.dart
index 7b7f135..6adc07b 100644
--- a/packages/flutter/test/services/platform_channel_test.dart
+++ b/packages/flutter/test/services/platform_channel_test.dart
@@ -12,7 +12,7 @@
     const MessageCodec<String?> string = StringCodec();
     const BasicMessageChannel<String?> channel = BasicMessageChannel<String?>('ch', string);
     test('can send string message and get reply', () async {
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
         'ch',
         (ByteData? message) async => string.encodeMessage(string.decodeMessage(message)! + ' world'),
       );
@@ -23,7 +23,7 @@
     test('can receive string message and send reply', () async {
       channel.setMessageHandler((String? message) async => message! + ' world');
       String? reply;
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         'ch',
         const StringCodec().encodeMessage('hello'),
         (ByteData? replyBinary) {
@@ -40,7 +40,7 @@
     const MethodChannel channel = MethodChannel('ch7', jsonMethod);
     const OptionalMethodChannel optionalMethodChannel = OptionalMethodChannel('ch8', jsonMethod);
     test('can invoke method and get result', () async {
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
         'ch7',
         (ByteData? message) async {
           final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
@@ -56,7 +56,7 @@
     });
 
     test('can invoke list method and get result', () async {
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
         'ch7',
         (ByteData? message) async {
           final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
@@ -72,7 +72,7 @@
     });
 
     test('can invoke list method and get null result', () async {
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
         'ch7',
         (ByteData? message) async {
           final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
@@ -87,7 +87,7 @@
     });
 
     test('can invoke map method and get result', () async {
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
         'ch7',
         (ByteData? message) async {
           final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
@@ -103,7 +103,7 @@
     });
 
     test('can invoke map method and get null result', () async {
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
         'ch7',
         (ByteData? message) async {
           final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
@@ -118,7 +118,7 @@
     });
 
     test('can invoke method and get error', () async {
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
         'ch7',
         (ByteData? message) async {
           return jsonMessage.encodeMessage(<dynamic>[
@@ -141,7 +141,7 @@
     });
 
     test('can invoke unimplemented method', () async {
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
         'ch7',
         (ByteData? message) async => null,
       );
@@ -157,7 +157,7 @@
     });
 
     test('can invoke unimplemented method (optional)', () async {
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
         'ch8',
         (ByteData? message) async => null,
       );
@@ -169,7 +169,7 @@
       channel.setMethodCallHandler(null);
       final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
       ByteData? envelope;
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
         envelope = result;
       });
       await null; // just in case there's something async happening
@@ -179,7 +179,7 @@
     test('can handle method call with no registered plugin (setting after)', () async {
       final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
       ByteData? envelope;
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
         envelope = result;
       });
       channel.setMethodCallHandler(null);
@@ -193,7 +193,7 @@
       });
       final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
       ByteData? envelope;
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
         envelope = result;
       });
       expect(envelope, isNull);
@@ -203,7 +203,7 @@
       channel.setMethodCallHandler((MethodCall call) async => '${call.arguments}, world');
       final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
       ByteData? envelope;
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
         envelope = result;
       });
       expect(jsonMethod.decodeEnvelope(envelope!), equals('hello, world'));
@@ -215,7 +215,7 @@
       });
       final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
       ByteData? envelope;
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
         envelope = result;
       });
       try {
@@ -235,7 +235,7 @@
       });
       final ByteData call = jsonMethod.encodeMethodCall(const MethodCall('sayHello', 'hello'));
       ByteData? envelope;
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('ch7', call, (ByteData? result) {
         envelope = result;
       });
       try {
@@ -249,24 +249,14 @@
       }
     });
 
-    test('can check the handler', () {
+    test('can check the mock handler', () async {
       Future<dynamic> handler(MethodCall call) => Future<dynamic>.value(null);
 
       const MethodChannel channel = MethodChannel('test_handler');
-      expect(channel.checkMethodCallHandler(null), true);
-      expect(channel.checkMethodCallHandler(handler), false);
-      channel.setMethodCallHandler(handler);
-      expect(channel.checkMethodCallHandler(handler), true);
-    });
-
-    test('can check the mock handler', () {
-      Future<dynamic> handler(MethodCall call) => Future<dynamic>.value(null);
-
-      const MethodChannel channel = MethodChannel('test_handler');
-      expect(channel.checkMockMethodCallHandler(null), true);
-      expect(channel.checkMockMethodCallHandler(handler), false);
-      channel.setMockMethodCallHandler(handler);
-      expect(channel.checkMockMethodCallHandler(handler), true);
+      expect(TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(channel.name, null), true);
+      expect(TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(channel.name, handler), false);
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(channel, handler);
+      expect(TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(channel.name, handler), true);
     });
   });
 
@@ -275,7 +265,7 @@
     const MethodCodec jsonMethod = JSONMethodCodec();
     const EventChannel channel = EventChannel('ch', jsonMethod);
     void emitEvent(ByteData? event) {
-      ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         'ch',
         event,
         (ByteData? reply) {},
@@ -283,7 +273,7 @@
     }
     test('can receive event stream', () async {
       bool canceled = false;
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
         'ch',
         (ByteData? message) async {
           final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
@@ -308,7 +298,7 @@
     });
 
     test('can receive error event', () async {
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
         'ch',
         (ByteData? message) async {
           final Map<dynamic, dynamic> methodCall = jsonMessage.decodeMessage(message) as Map<dynamic, dynamic>;
diff --git a/packages/flutter/test/services/platform_messages_test.dart b/packages/flutter/test/services/platform_messages_test.dart
index 9aa9bf1..8fd3937 100644
--- a/packages/flutter/test/services/platform_messages_test.dart
+++ b/packages/flutter/test/services/platform_messages_test.dart
@@ -7,24 +7,23 @@
 import 'package:flutter_test/flutter_test.dart';
 
 void main() {
-  test('Mock binary message handler control test', () async {
-    // Initialize all bindings because defaultBinaryMessenger.send() needs a window.
-    TestWidgetsFlutterBinding.ensureInitialized();
+  TestWidgetsFlutterBinding.ensureInitialized();
 
+  test('Mock binary message handler control test', () async {
     final List<ByteData?> log = <ByteData>[];
 
-    ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('test1', (ByteData? message) async {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('test1', (ByteData? message) async {
       log.add(message);
       return null;
     });
 
     final ByteData message = ByteData(2)..setUint16(0, 0xABCD);
-    await ServicesBinding.instance!.defaultBinaryMessenger.send('test1', message);
+    await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.send('test1', message);
     expect(log, equals(<ByteData>[message]));
     log.clear();
 
-    ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('test1', null);
-    await ServicesBinding.instance!.defaultBinaryMessenger.send('test1', message);
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('test1', null);
+    await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.send('test1', message);
     expect(log, isEmpty);
   });
 }
diff --git a/packages/flutter/test/services/raw_keyboard_test.dart b/packages/flutter/test/services/raw_keyboard_test.dart
index 7f65991..3bbc185 100644
--- a/packages/flutter/test/services/raw_keyboard_test.dart
+++ b/packages/flutter/test/services/raw_keyboard_test.dart
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-
 import 'package:flutter/foundation.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter/widgets.dart';
@@ -30,6 +29,7 @@
         RawKeyboard.instance.removeListener(handleKey);
       }
     });
+
     testWidgets('No character is produced for non-printables', (WidgetTester tester) async {
       for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows', 'web']) {
         void handleKey(RawKeyEvent event) {
@@ -40,6 +40,7 @@
         RawKeyboard.instance.removeListener(handleKey);
       }
     });
+
     testWidgets('keysPressed is maintained', (WidgetTester tester) async {
       for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows', 'ios']) {
         RawKeyboard.instance.clearKeysPressed();
@@ -209,7 +210,7 @@
       // when this event is received, but it's not in keysPressed yet.
       data['modifiers'] |= RawKeyEventDataMacOs.modifierLeftShift | RawKeyEventDataMacOs.modifierShift;
       // dispatch the modified data.
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
         (ByteData? data) {},
@@ -234,7 +235,7 @@
       // when this event is received, but it's not in keysPressed yet.
       data['modifiers'] |= RawKeyEventDataMacOs.modifierLeftShift | RawKeyEventDataMacOs.modifierShift;
       // dispatch the modified data.
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
         (ByteData? data) {},
@@ -259,7 +260,7 @@
       // when this event is received, but it's not in keysPressed yet.
       data['modifiers'] |= RawKeyEventDataWindows.modifierLeftShift | RawKeyEventDataWindows.modifierShift;
       // dispatch the modified data.
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
         (ByteData? data) {},
@@ -284,7 +285,7 @@
       // when this event is received, but it's not in keysPressed yet.
       data['metaState'] |= RawKeyEventDataAndroid.modifierLeftShift | RawKeyEventDataAndroid.modifierShift;
       // dispatch the modified data.
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
         (ByteData? data) {},
@@ -309,7 +310,7 @@
       // when this event is received, but it's not in keysPressed yet.
       data['modifiers'] |= RawKeyEventDataFuchsia.modifierLeftShift;
       // dispatch the modified data.
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
         (ByteData? data) {},
@@ -334,7 +335,7 @@
       // when this event is received, but it's not in keysPressed yet.
       data['modifiers'] |= GLFWKeyHelper.modifierShift;
       // dispatch the modified data.
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
         (ByteData? data) {},
@@ -364,7 +365,7 @@
         isDown: true,
       )..['metaState'] |= RawKeyEventDataWeb.modifierShift;
       // Dispatch the modified data.
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
         (ByteData? data) {},
@@ -456,7 +457,7 @@
         RawKeyEventDataAndroid.modifierControl |
         RawKeyEventDataAndroid.modifierMeta;
       // dispatch the modified data.
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
             (ByteData? data) {},
@@ -494,7 +495,7 @@
           RawKeyEventDataMacOs.modifierCommand |
           RawKeyEventDataMacOs.modifierControl;
       // dispatch the modified data.
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
             (ByteData? data) {},
@@ -570,7 +571,7 @@
           RawKeyEventDataWindows.modifierAlt |
           RawKeyEventDataWindows.modifierControl;
       // dispatch the modified data.
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
             (ByteData? data) {},
@@ -607,7 +608,7 @@
         GLFWKeyHelper.modifierControl |
         GLFWKeyHelper.modifierMeta;
       // dispatch the modified data.
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
             (ByteData? data) {},
@@ -645,7 +646,7 @@
         RawKeyEventDataWeb.modifierControl |
         RawKeyEventDataWeb.modifierMeta;
       // dispatch the modified data.
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
             (ByteData? data) {},
@@ -665,12 +666,6 @@
     });
 
     testWidgets('RawKeyboard asserts if no keys are in keysPressed after receiving a key down event', (WidgetTester tester) async {
-      FlutterErrorDetails? errorDetails;
-      final FlutterExceptionHandler? oldHandler = FlutterError.onError;
-      FlutterError.onError = (FlutterErrorDetails details) {
-        errorDetails = details;
-      };
-
       final Map<String, dynamic> keyEventMessage;
       if (kIsWeb) {
         keyEventMessage = const <String, dynamic>{
@@ -692,19 +687,15 @@
       }
 
       try {
-        await ServicesBinding.instance!.defaultBinaryMessenger
-            .handlePlatformMessage(
+        await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
           SystemChannels.keyEvent.name,
           SystemChannels.keyEvent.codec.encodeMessage(keyEventMessage),
-              (ByteData? data) {},
+          (ByteData? data) { },
         );
-      } finally {
-        FlutterError.onError = oldHandler;
+        fail('Expected an exception, but did not get one.');
+      } on AssertionError catch (error) {
+        expect(error.toString(), contains('Attempted to send a key down event when no keys are in keysPressed'));
       }
-      expect(errorDetails, isNotNull);
-      expect(errorDetails!.stack, isNotNull);
-      final String fullErrorMessage = errorDetails.toString().replaceAll('\n', ' ');
-      expect(fullErrorMessage, contains('Attempted to send a key down event when no keys are in keysPressed'));
     });
   });
 
@@ -757,6 +748,7 @@
         }
       }
     });
+
     test('modifier keys are recognized when combined', () {
       for (final int modifier in modifierTests.keys) {
         if (modifier == RawKeyEventDataAndroid.modifierFunction) {
@@ -799,6 +791,7 @@
         }
       }
     });
+
     test('Printable keyboard keys are correctly translated', () {
       final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(<String, dynamic>{
         'type': 'keydown',
@@ -817,6 +810,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
       expect(data.keyLabel, equals('a'));
     });
+
     test('Control keyboard keys are correctly translated', () {
       final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -833,6 +827,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
       expect(data.keyLabel, isEmpty);
     });
+
     test('Modifier keyboard keys are correctly translated', () {
       final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -850,6 +845,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft));
       expect(data.keyLabel, isEmpty);
     });
+
     test('DPAD keys from a joystick give physical key mappings', () {
       final RawKeyEvent joystickDpadDown = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -867,6 +863,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.arrowDown));
       expect(data.keyLabel, isEmpty);
     });
+
     test('Arrow keys from a keyboard give correct physical key mappings', () {
       final RawKeyEvent joystickDpadDown = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -883,6 +880,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.arrowDown));
       expect(data.keyLabel, isEmpty);
     });
+
     test('DPAD center from a game pad gives physical key mappings', () {
       final RawKeyEvent joystickDpadCenter = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -900,6 +898,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.select));
       expect(data.keyLabel, isEmpty);
     });
+
     test('Device id is read from message', () {
       final RawKeyEvent joystickDpadCenter = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -915,6 +914,7 @@
       final RawKeyEventDataAndroid data = joystickDpadCenter.data as RawKeyEventDataAndroid;
       expect(data.deviceId, equals(10));
     });
+
     test('Repeat count is passed correctly', () {
       final RawKeyEvent repeatCountEvent = RawKeyEvent.fromMessage(<String, dynamic>{
         'type': 'keydown',
@@ -931,6 +931,7 @@
       final RawKeyEventDataAndroid data = repeatCountEvent.data as RawKeyEventDataAndroid;
       expect(data.repeatCount, equals(42));
     });
+
     testWidgets('Key events are responded to correctly.', (WidgetTester tester) async {
       expect(RawKeyboard.instance.keysPressed, isEmpty);
       // Generate the data for a regular key down event.
@@ -940,7 +941,7 @@
         isDown: true,
       );
       Map<String, dynamic>? message;
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
         (ByteData? data) {
@@ -963,7 +964,7 @@
       focusNode.requestFocus();
       await tester.pump();
 
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
         (ByteData? data) {
@@ -971,7 +972,7 @@
         },
       );
       expect(message, equals(<String, dynamic>{ 'handled': true }));
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(SystemChannels.keyEvent.name, null);
+      tester.binding.defaultBinaryMessenger.setMockMessageHandler(SystemChannels.keyEvent.name, null);
     });
   }, skip: isBrowser); // This is an Android-specific group.
 
@@ -1019,6 +1020,7 @@
         }
       }
     });
+
     test('modifier keys are recognized when combined', () {
       for (final int modifier in modifierTests.keys) {
         if (modifier == RawKeyEventDataFuchsia.modifierCapsLock) {
@@ -1052,6 +1054,7 @@
         }
       }
     });
+
     test('Printable keyboard keys are correctly translated', () {
       final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(<String, dynamic>{
         'type': 'keydown',
@@ -1065,6 +1068,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
       expect(data.keyLabel, equals('a'));
     });
+
     test('Control keyboard keys are correctly translated', () {
       final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -1136,6 +1140,7 @@
         }
       }
     });
+
     test('modifier keys are recognized when combined', () {
       for (final int modifier in modifierTests.keys) {
         if (modifier == RawKeyEventDataMacOs.modifierCapsLock) {
@@ -1175,6 +1180,7 @@
         }
       }
     });
+
     test('Printable keyboard keys are correctly translated', () {
       const String unmodifiedCharacter = 'a';
       final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
@@ -1190,6 +1196,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
       expect(data.keyLabel, equals('a'));
     });
+
     test('Control keyboard keys are correctly translated', () {
       final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -1281,6 +1288,7 @@
         }
       }
     });
+
     test('modifier keys are recognized when combined', () {
       for (final int modifier in modifierTests.keys) {
         if (modifier == RawKeyEventDataIos.modifierCapsLock) {
@@ -1320,6 +1328,7 @@
         }
       }
     });
+
     test('Printable keyboard keys are correctly translated', () {
       const String unmodifiedCharacter = 'a';
       final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
@@ -1335,6 +1344,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
       expect(data.keyLabel, equals('a'));
     });
+
     test('Control keyboard keys are correctly translated', () {
       final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -1427,6 +1437,7 @@
         }
       }
     });
+
     test('modifier keys are recognized when combined', () {
       for (final int modifier in modifierTests.keys) {
         if (modifier == RawKeyEventDataWindows.modifierCaps) {
@@ -1466,6 +1477,7 @@
         }
       }
     });
+
     test('Printable keyboard keys are correctly translated', () {
       const int unmodifiedCharacter = 97; // ASCII value for 'a'.
       final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
@@ -1481,6 +1493,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
       expect(data.keyLabel, equals('a'));
     });
+
     test('Control keyboard keys are correctly translated', () {
       final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -1495,6 +1508,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
       expect(data.keyLabel, isEmpty);
     });
+
     test('Modifier keyboard keys are correctly translated', () {
       final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -1509,6 +1523,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft));
       expect(data.keyLabel, isEmpty);
     });
+
     test('Unprintable keyboard keys are correctly translated', () {
       final RawKeyEvent leftArrowKey = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -1522,6 +1537,7 @@
       expect(data.physicalKey, equals(PhysicalKeyboardKey.arrowLeft));
       expect(data.logicalKey, equals(LogicalKeyboardKey.arrowLeft));
     });
+
     testWidgets('Win32 VK_PROCESSKEY events are skipped', (WidgetTester tester) async {
       const  String platform = 'windows';
       bool lastHandled = true;
@@ -1620,6 +1636,7 @@
         }
       }
     });
+
     test('modifier keys are recognized when combined', () {
       for (final int modifier in modifierTests.keys) {
         if (modifier == GLFWKeyHelper.modifierControl) {
@@ -1660,6 +1677,7 @@
         }
       }
     });
+
     test('Printable keyboard keys are correctly translated', () {
       final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -1675,6 +1693,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.keyQ));
       expect(data.keyLabel, equals('q'));
     });
+
     test('Code points with two Unicode scalar values are allowed', () {
       final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -1723,6 +1742,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
       expect(data.keyLabel, isEmpty);
     });
+
     test('Modifier keyboard keys are correctly translated', () {
       final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -1804,6 +1824,7 @@
         }
       }
     });
+
     test('modifier keys are recognized when combined', () {
       for (final int modifier in modifierTests.keys) {
         if (modifier == GtkKeyHelper.modifierControl) {
@@ -1844,6 +1865,7 @@
         }
       }
     });
+
     test('Printable keyboard keys are correctly translated', () {
       final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -1859,6 +1881,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.keyQ));
       expect(data.keyLabel, equals('q'));
     });
+
     test('Code points with two Unicode scalar values are allowed', () {
       final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -1907,6 +1930,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
       expect(data.keyLabel, isEmpty);
     });
+
     test('Modifier keyboard keys are correctly translated', () {
       final RawKeyEvent shiftLeftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -1960,6 +1984,7 @@
         }
       }
     });
+
     test('modifier keys are recognized when combined', () {
       for (final int modifier in modifierTests.keys) {
         if (modifier == RawKeyEventDataWeb.modifierMeta) {
@@ -1992,6 +2017,7 @@
         }
       }
     });
+
     test('Printable keyboard keys are correctly translated', () {
       final RawKeyEvent keyAEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -2005,6 +2031,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.keyA));
       expect(data.keyLabel, equals('a'));
     });
+
     test('Control keyboard keys are correctly translated', () {
       final RawKeyEvent escapeKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -2017,6 +2044,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.escape));
       expect(data.keyLabel, isEmpty);
     });
+
     test('Modifier keyboard keys are correctly translated', () {
       final RawKeyEvent shiftKeyEvent = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
@@ -2029,6 +2057,7 @@
       expect(data.logicalKey, equals(LogicalKeyboardKey.shiftLeft));
       expect(data.keyLabel, isEmpty);
     });
+
     test('Arrow keys from a keyboard give correct physical key mappings', () {
       final RawKeyEvent arrowKeyDown = RawKeyEvent.fromMessage(const <String, dynamic>{
         'type': 'keydown',
diff --git a/packages/flutter/test/services/restoration_test.dart b/packages/flutter/test/services/restoration_test.dart
index 70e197f..cc13230 100644
--- a/packages/flutter/test/services/restoration_test.dart
+++ b/packages/flutter/test/services/restoration_test.dart
@@ -18,7 +18,7 @@
     testWidgets('root bucket retrieval', (WidgetTester tester) async {
       final List<MethodCall> callsToEngine = <MethodCall>[];
       final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
-      SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) {
+      tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) {
         callsToEngine.add(call);
         return result.future;
       });
@@ -64,7 +64,7 @@
     testWidgets('root bucket received from engine before retrieval', (WidgetTester tester) async {
       SystemChannels.restoration.setMethodCallHandler(null);
       final List<MethodCall> callsToEngine = <MethodCall>[];
-      SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) async {
+      tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) async {
         callsToEngine.add(call);
       });
       final RestorationManager manager = RestorationManager();
@@ -83,7 +83,7 @@
       SystemChannels.restoration.setMethodCallHandler(null);
       final List<MethodCall> callsToEngine = <MethodCall>[];
       final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
-      SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) {
+      tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) {
         callsToEngine.add(call);
         return result.future;
       });
@@ -110,7 +110,7 @@
     });
 
     testWidgets('root bucket is properly replaced when new data is available', (WidgetTester tester) async {
-      SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) async {
+      tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) async {
         return _createEncodedRestorationData1();
       });
       final RestorationManager manager = RestorationManager();
@@ -152,7 +152,7 @@
     testWidgets('returns null as root bucket when restoration is disabled', (WidgetTester tester) async {
       final List<MethodCall> callsToEngine = <MethodCall>[];
       final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
-      SystemChannels.restoration.setMockMethodCallHandler((MethodCall call)  {
+      tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call)  {
         callsToEngine.add(call);
         return result.future;
       });
@@ -195,7 +195,7 @@
     testWidgets('flushData', (WidgetTester tester) async {
       final List<MethodCall> callsToEngine = <MethodCall>[];
       final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
-      SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) {
+      tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) {
         callsToEngine.add(call);
         return result.future;
       });
@@ -230,7 +230,7 @@
 
     testWidgets('isReplacing', (WidgetTester tester) async {
       final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>();
-      SystemChannels.restoration.setMockMethodCallHandler((MethodCall call) {
+      tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) {
         return result.future;
       });
 
diff --git a/packages/flutter/test/services/system_chrome_test.dart b/packages/flutter/test/services/system_chrome_test.dart
index b05f7a1..81130cd 100644
--- a/packages/flutter/test/services/system_chrome_test.dart
+++ b/packages/flutter/test/services/system_chrome_test.dart
@@ -7,6 +7,8 @@
 import 'package:flutter_test/flutter_test.dart';
 
 void main() {
+  TestWidgetsFlutterBinding.ensureInitialized();
+
   testWidgets('SystemChrome overlay style test', (WidgetTester tester) async {
     // The first call is a cache miss and will queue a microtask
     SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);
@@ -24,7 +26,7 @@
   test('setPreferredOrientations control test', () async {
     final List<MethodCall> log = <MethodCall>[];
 
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -42,7 +44,7 @@
   test('setApplicationSwitcherDescription control test', () async {
     final List<MethodCall> log = <MethodCall>[];
 
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -60,7 +62,7 @@
   test('setApplicationSwitcherDescription missing plugin', () async {
     final List<ByteData?> log = <ByteData>[];
 
-    ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/platform', (ByteData? message) async {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler('flutter/platform', (ByteData? message) async {
       log.add(message);
     });
 
@@ -74,7 +76,7 @@
   test('setEnabledSystemUIOverlays control test', () async {
     final List<MethodCall> log = <MethodCall>[];
 
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
diff --git a/packages/flutter/test/services/system_navigator_test.dart b/packages/flutter/test/services/system_navigator_test.dart
index a4d369f..122c1ca 100644
--- a/packages/flutter/test/services/system_navigator_test.dart
+++ b/packages/flutter/test/services/system_navigator_test.dart
@@ -18,7 +18,7 @@
   }
 
   test('System navigator control test - platform messages', () async {
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -26,11 +26,11 @@
       isMethodCall('SystemNavigator.pop', arguments: null),
     ]);
 
-    SystemChannels.platform.setMockMethodCallHandler(null);
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
   });
 
   test('System navigator control test - navigation messages', () async {
-    SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -54,6 +54,6 @@
       isMethodCall('routeUpdated', arguments: <String, dynamic>{ 'routeName': 'a', 'previousRouteName': 'b' }),
     ]);
 
-    SystemChannels.navigation.setMockMethodCallHandler(null);
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, null);
   });
 }
diff --git a/packages/flutter/test/services/system_sound_test.dart b/packages/flutter/test/services/system_sound_test.dart
index 20a6d5a..823d7f0 100644
--- a/packages/flutter/test/services/system_sound_test.dart
+++ b/packages/flutter/test/services/system_sound_test.dart
@@ -12,7 +12,7 @@
   test('System sound control test', () async {
     final List<MethodCall> log = <MethodCall>[];
 
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
diff --git a/packages/flutter/test/services/text_input_test.dart b/packages/flutter/test/services/text_input_test.dart
index 20ad74a..71aa1d2 100644
--- a/packages/flutter/test/services/text_input_test.dart
+++ b/packages/flutter/test/services/text_input_test.dart
@@ -466,16 +466,6 @@
   @override
   void setMethodCallHandler(Future<void> Function(MethodCall call)? handler) => incoming = handler;
 
-  @override
-  bool checkMethodCallHandler(Future<void> Function(MethodCall call)? handler) => throw UnimplementedError();
-
-
-  @override
-  void setMockMethodCallHandler(Future<void>? Function(MethodCall call)? handler)  => throw UnimplementedError();
-
-  @override
-  bool checkMockMethodCallHandler(Future<void> Function(MethodCall call)? handler) => throw UnimplementedError();
-
   void validateOutgoingMethodCalls(List<MethodCall> calls) {
     expect(outgoingCalls.length, calls.length);
     bool hasError = false;
diff --git a/packages/flutter/test/widgets/draggable_test.dart b/packages/flutter/test/widgets/draggable_test.dart
index 5879aba..ef50d70 100644
--- a/packages/flutter/test/widgets/draggable_test.dart
+++ b/packages/flutter/test/widgets/draggable_test.dart
@@ -3107,7 +3107,7 @@
   bool onDragStartedCalled = false;
 
   int hapticFeedbackCalls = 0;
-  SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+  tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
     if (methodCall.method == 'HapticFeedback.vibrate') {
       hapticFeedbackCalls++;
     }
diff --git a/packages/flutter/test/widgets/editable_text_cursor_test.dart b/packages/flutter/test/widgets/editable_text_cursor_test.dart
index b05571a..b069b4e 100644
--- a/packages/flutter/test/widgets/editable_text_cursor_test.dart
+++ b/packages/flutter/test/widgets/editable_text_cursor_test.dart
@@ -79,7 +79,7 @@
 
     // Populate a fake clipboard.
     const String clipboardContent = ' ';
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       if (methodCall.method == 'Clipboard.getData')
         return const <String, dynamic>{'text': clipboardContent};
       return null;
@@ -131,7 +131,7 @@
 
     // Populate a fake clipboard.
     const String clipboardContent = ' ';
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       if (methodCall.method == 'Clipboard.getData')
         return const <String, dynamic>{'text': clipboardContent};
       return null;
@@ -853,7 +853,7 @@
 
     // Populate a fake clipboard.
     const String clipboardContent = 'Hello world!';
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       if (methodCall.method == 'Clipboard.getData')
         return const <String, dynamic>{'text': clipboardContent};
       return null;
@@ -911,7 +911,7 @@
 
     // Populate a fake clipboard.
     const String clipboardContent = 'Hello world!';
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       if (methodCall.method == 'Clipboard.getData')
         return const <String, dynamic>{'text': clipboardContent};
       return null;
diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart
index 5971eb3..74fd79d 100644
--- a/packages/flutter/test/widgets/editable_text_test.dart
+++ b/packages/flutter/test/widgets/editable_text_test.dart
@@ -65,9 +65,9 @@
 }
 
 void main() {
-  TestWidgetsFlutterBinding.ensureInitialized();
   final MockClipboard mockClipboard = MockClipboard();
-  SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
+  (TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding)
+    .defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
 
   setUp(() async {
     debugResetSemanticsIdCounter();
@@ -1982,7 +1982,7 @@
     await tester.pump(); // An extra pump to allow focus request to go through.
 
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -3234,7 +3234,7 @@
     // Regression test for https://github.com/flutter/flutter/issues/22212.
 
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -3265,7 +3265,7 @@
 
   testWidgets('location of widget is sent on show keyboard', (WidgetTester tester) async {
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -3302,7 +3302,7 @@
 
   testWidgets('transform and size is reset when text connection opens', (WidgetTester tester) async {
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -3390,7 +3390,7 @@
 
   testWidgets('size and transform are sent when they change', (WidgetTester tester) async {
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -3432,7 +3432,7 @@
 
   testWidgets('text styling info is sent on show keyboard', (WidgetTester tester) async {
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -3519,7 +3519,7 @@
     await tester.showKeyboard(find.byType(EditableText));
 
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
       log.add(methodCall);
     });
     setState(() {
@@ -3748,7 +3748,7 @@
     // Regression test for https://github.com/flutter/flutter/issues/22212.
 
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -5720,7 +5720,7 @@
   testWidgets('Synchronous test of local and remote editing values', (WidgetTester tester) async {
     // Regression test for https://github.com/flutter/flutter/issues/65059
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
       log.add(methodCall);
     });
     final TextInputFormatter formatter = TextInputFormatter.withFunction((TextEditingValue oldValue, TextEditingValue newValue) {
@@ -5848,7 +5848,7 @@
   testWidgets('Send text input state to engine when the input formatter rejects user input', (WidgetTester tester) async {
     // Regression test for https://github.com/flutter/flutter/issues/67828
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
       log.add(methodCall);
     });
     final TextInputFormatter formatter = TextInputFormatter.withFunction((TextEditingValue oldValue, TextEditingValue newValue) {
@@ -5927,7 +5927,7 @@
   testWidgets('Repeatedly receiving [TextEditingValue] will not trigger a keyboard request', (WidgetTester tester) async {
     // Regression test for https://github.com/flutter/flutter/issues/66036
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
       log.add(methodCall);
     });
     final TextEditingController controller = TextEditingController();
@@ -6048,7 +6048,7 @@
     testWidgets('TextEditingController.clear() behavior test', (WidgetTester tester) async {
       // Regression test for https://github.com/flutter/flutter/issues/66316
       final List<MethodCall> log = <MethodCall>[];
-      SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async {
+      tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async {
         log.add(methodCall);
       });
       final TextEditingController controller = TextEditingController();
diff --git a/packages/flutter/test/widgets/modal_barrier_test.dart b/packages/flutter/test/widgets/modal_barrier_test.dart
index 310ec98..050941d 100644
--- a/packages/flutter/test/widgets/modal_barrier_test.dart
+++ b/packages/flutter/test/widgets/modal_barrier_test.dart
@@ -159,7 +159,7 @@
   testWidgets('ModalBarrier plays system alert sound when user tries to dismiss it', (WidgetTester tester) async {
     final List<String> playedSystemSounds = <String>[];
     try {
-      SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+      tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
         if (methodCall.method == 'SystemSound.play')
           playedSystemSounds.add(methodCall.arguments as String);
       });
@@ -176,7 +176,7 @@
       await tester.tap(find.text('target'), warnIfMissed: false);
       await tester.pumpWidget(subject);
     } finally {
-      SystemChannels.platform.setMockMethodCallHandler(null);
+      tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
     }
     expect(playedSystemSounds, hasLength(1));
     expect(playedSystemSounds[0], SystemSoundType.alert.toString());
diff --git a/packages/flutter/test/widgets/mouse_region_test.dart b/packages/flutter/test/widgets/mouse_region_test.dart
index 487638c..d9eec08 100644
--- a/packages/flutter/test/widgets/mouse_region_test.dart
+++ b/packages/flutter/test/widgets/mouse_region_test.dart
@@ -1591,7 +1591,7 @@
     final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse);
     await gesture.addPointer(location: const Offset(100, 100));
     addTearDown(gesture.removePointer);
-    SystemChannels.mouseCursor.setMockMethodCallHandler((_) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.mouseCursor, (_) async {
       logCursors.add('cursor');
     });
 
diff --git a/packages/flutter/test/widgets/platform_view_test.dart b/packages/flutter/test/widgets/platform_view_test.dart
index 16303ea..e7c77d9 100644
--- a/packages/flutter/test/widgets/platform_view_test.dart
+++ b/packages/flutter/test/widgets/platform_view_test.dart
@@ -1075,7 +1075,7 @@
       await tester.pump();
 
       late int lastPlatformViewTextClient;
-      SystemChannels.textInput.setMockMethodCallHandler((MethodCall call) {
+      tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall call) {
         if (call.method == 'TextInput.setPlatformViewClient') {
           lastPlatformViewTextClient = call.arguments as int;
         }
diff --git a/packages/flutter/test/widgets/route_notification_messages_test.dart b/packages/flutter/test/widgets/route_notification_messages_test.dart
index 3aa1e21..891189d 100644
--- a/packages/flutter/test/widgets/route_notification_messages_test.dart
+++ b/packages/flutter/test/widgets/route_notification_messages_test.dart
@@ -55,7 +55,7 @@
 
     final List<MethodCall> log = <MethodCall>[];
 
-    SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -110,7 +110,7 @@
 
   testWidgets('Navigator does not report route name by default', (WidgetTester tester) async {
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -160,7 +160,7 @@
 
     final List<MethodCall> log = <MethodCall>[];
 
-    SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -215,7 +215,7 @@
 
   testWidgets('Nameless routes should send platform messages', (WidgetTester tester) async {
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
@@ -257,7 +257,7 @@
 
   testWidgets('PlatformRouteInformationProvider reports URL', (WidgetTester tester) async {
     final List<MethodCall> log = <MethodCall>[];
-    SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
diff --git a/packages/flutter/test/widgets/selectable_text_test.dart b/packages/flutter/test/widgets/selectable_text_test.dart
index 9f454ca..d05f943 100644
--- a/packages/flutter/test/widgets/selectable_text_test.dart
+++ b/packages/flutter/test/widgets/selectable_text_test.dart
@@ -124,7 +124,7 @@
 void main() {
   TestWidgetsFlutterBinding.ensureInitialized();
   final MockClipboard mockClipboard = MockClipboard();
-  SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
+  TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
 
   const String kThreeLines =
       'First line of text is\n'
@@ -1665,7 +1665,7 @@
     final FocusNode focusNode = FocusNode();
 
     String clipboardContent = '';
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       if (methodCall.method == 'Clipboard.setData')
         clipboardContent = methodCall.arguments['text'] as String;
       else if (methodCall.method == 'Clipboard.getData')
diff --git a/packages/flutter/test/widgets/text_selection_test.dart b/packages/flutter/test/widgets/text_selection_test.dart
index 8192d15..48107e8 100644
--- a/packages/flutter/test/widgets/text_selection_test.dart
+++ b/packages/flutter/test/widgets/text_selection_test.dart
@@ -19,15 +19,15 @@
     'text': null,
   };
 
-  Future<dynamic> handleMethodCall(MethodCall methodCall) async {
+  Future<Object?> handleMethodCall(MethodCall methodCall) async {
     switch (methodCall.method) {
       case 'Clipboard.getData':
-        if (getDataThrows) {
+        if (getDataThrows)
           throw Exception();
-        }
         return _clipboardData;
       case 'Clipboard.setData':
         _clipboardData = methodCall.arguments;
+        break;
     }
   }
 }
@@ -758,11 +758,11 @@
     group('when Clipboard fails', () {
       setUp(() {
         final MockClipboard mockClipboard = MockClipboard(getDataThrows: true);
-        SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
+        TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
       });
 
       tearDown(() {
-        SystemChannels.platform.setMockMethodCallHandler(null);
+        TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
       });
 
       test('Clipboard API failure is gracefully recovered from', () async {
@@ -778,11 +778,11 @@
       final MockClipboard mockClipboard = MockClipboard();
 
       setUp(() {
-        SystemChannels.platform.setMockMethodCallHandler(mockClipboard.handleMethodCall);
+        TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
       });
 
       tearDown(() {
-        SystemChannels.platform.setMockMethodCallHandler(null);
+        TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
       });
 
       test('update sets value based on clipboard contents', () async {
diff --git a/packages/flutter/test/widgets/title_test.dart b/packages/flutter/test/widgets/title_test.dart
index fd5cc56..2fe657d 100644
--- a/packages/flutter/test/widgets/title_test.dart
+++ b/packages/flutter/test/widgets/title_test.dart
@@ -36,7 +36,7 @@
   testWidgets('should not pass "null" to setApplicationSwitcherDescription', (WidgetTester tester) async {
     final List<MethodCall> log = <MethodCall>[];
 
-    SystemChannels.platform.setMockMethodCallHandler((MethodCall methodCall) async {
+    tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
       log.add(methodCall);
     });
 
diff --git a/packages/flutter_driver/lib/src/extension/extension.dart b/packages/flutter_driver/lib/src/extension/extension.dart
index 2150a6e..c9caa19 100644
--- a/packages/flutter_driver/lib/src/extension/extension.dart
+++ b/packages/flutter_driver/lib/src/extension/extension.dart
@@ -30,7 +30,7 @@
 /// eventually completes to a string response.
 typedef DataHandler = Future<String> Function(String? message);
 
-class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
+class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, GestureBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding, TestDefaultBinaryMessengerBinding {
   _DriverBinding(this._handler, this._silenceErrors, this._enableTextEntryEmulation, this.finders, this.commands);
 
   final DataHandler? _handler;
@@ -51,11 +51,6 @@
       registerWebServiceExtension(extension.call);
     }
   }
-
-  @override
-  BinaryMessenger createBinaryMessenger() {
-    return TestDefaultBinaryMessenger(super.createBinaryMessenger());
-  }
 }
 
 /// Enables Flutter Driver VM service extension.
@@ -330,11 +325,11 @@
       registerTextInput();
     }
 
-    for(final FinderExtension finder in finders) {
+    for (final FinderExtension finder in finders) {
       _finderExtensions[finder.finderType] = finder;
     }
 
-    for(final CommandExtension command in commands) {
+    for (final CommandExtension command in commands) {
       _commandExtensions[command.commandKind] = command;
     }
   }
@@ -418,7 +413,7 @@
   @override
   Command deserializeCommand(Map<String, String> params, DeserializeFinderFactory finderFactory) {
     final String? kind = params['command'];
-    if(_commandExtensions.containsKey(kind)) {
+    if (_commandExtensions.containsKey(kind)) {
       return _commandExtensions[kind]!.deserialize(params, finderFactory, this);
     }
 
@@ -434,7 +429,7 @@
   @override
   Future<Result> handleCommand(Command command, WidgetController prober, CreateFinderFactory finderFactory) {
     final String kind = command.kind;
-    if(_commandExtensions.containsKey(kind)) {
+    if (_commandExtensions.containsKey(kind)) {
       return _commandExtensions[kind]!.call(command, prober, finderFactory, this);
     }
 
diff --git a/packages/flutter_driver/test/src/real_tests/extension_test.dart b/packages/flutter_driver/test/src/real_tests/extension_test.dart
index 9a1dd8f..8242512 100644
--- a/packages/flutter_driver/test/src/real_tests/extension_test.dart
+++ b/packages/flutter_driver/test/src/real_tests/extension_test.dart
@@ -279,7 +279,7 @@
         'waiting for NoPendingPlatformMessages returns until a single method channel call returns', (WidgetTester tester) async {
       const MethodChannel channel = MethodChannel('helloChannel', JSONMethodCodec());
       const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      tester.binding.defaultBinaryMessenger.setMockMessageHandler(
           'helloChannel', (ByteData? message) {
             return Future<ByteData>.delayed(
                 const Duration(milliseconds: 10),
@@ -313,7 +313,7 @@
       const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
       // Configures channel 1
       const MethodChannel channel1 = MethodChannel('helloChannel1', JSONMethodCodec());
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      tester.binding.defaultBinaryMessenger.setMockMessageHandler(
           'helloChannel1', (ByteData? message) {
             return Future<ByteData>.delayed(
                 const Duration(milliseconds: 10),
@@ -322,7 +322,7 @@
 
       // Configures channel 2
       const MethodChannel channel2 = MethodChannel('helloChannel2', JSONMethodCodec());
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      tester.binding.defaultBinaryMessenger.setMockMessageHandler(
           'helloChannel2', (ByteData? message) {
             return Future<ByteData>.delayed(
                 const Duration(milliseconds: 20),
@@ -362,7 +362,7 @@
       const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
       // Configures channel 1
       const MethodChannel channel1 = MethodChannel('helloChannel1', JSONMethodCodec());
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      tester.binding.defaultBinaryMessenger.setMockMessageHandler(
           'helloChannel1', (ByteData? message) {
             return Future<ByteData>.delayed(
                 const Duration(milliseconds: 10),
@@ -371,7 +371,7 @@
 
       // Configures channel 2
       const MethodChannel channel2 = MethodChannel('helloChannel2', JSONMethodCodec());
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      tester.binding.defaultBinaryMessenger.setMockMessageHandler(
           'helloChannel2', (ByteData? message) {
             return Future<ByteData>.delayed(
                 const Duration(milliseconds: 20),
@@ -413,7 +413,7 @@
       const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
       // Configures channel 1
       const MethodChannel channel1 = MethodChannel('helloChannel1', JSONMethodCodec());
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      tester.binding.defaultBinaryMessenger.setMockMessageHandler(
           'helloChannel1', (ByteData? message) {
             return Future<ByteData>.delayed(
                 const Duration(milliseconds: 20),
@@ -422,7 +422,7 @@
 
       // Configures channel 2
       const MethodChannel channel2 = MethodChannel('helloChannel2', JSONMethodCodec());
-      ServicesBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(
+      tester.binding.defaultBinaryMessenger.setMockMessageHandler(
           'helloChannel2', (ByteData? message) {
             return Future<ByteData>.delayed(
                 const Duration(milliseconds: 10),
diff --git a/packages/flutter_test/lib/flutter_test.dart b/packages/flutter_test/lib/flutter_test.dart
index fbeb6f1..d7531ff 100644
--- a/packages/flutter_test/lib/flutter_test.dart
+++ b/packages/flutter_test/lib/flutter_test.dart
@@ -61,6 +61,7 @@
 export 'src/animation_sheet.dart';
 export 'src/binding.dart';
 export 'src/controller.dart';
+export 'src/deprecated.dart';
 export 'src/event_simulation.dart';
 export 'src/finders.dart';
 export 'src/frame_timing_summarizer.dart';
@@ -73,6 +74,7 @@
 export 'src/stack_manipulation.dart';
 export 'src/test_async_utils.dart';
 export 'src/test_compat.dart';
+export 'src/test_default_binary_messenger.dart';
 export 'src/test_exception_reporter.dart';
 export 'src/test_pointer.dart';
 export 'src/test_text_input.dart';
diff --git a/packages/flutter_test/lib/src/_binding_io.dart b/packages/flutter_test/lib/src/_binding_io.dart
index 19ec7db..f09b3e1 100644
--- a/packages/flutter_test/lib/src/_binding_io.dart
+++ b/packages/flutter_test/lib/src/_binding_io.dart
@@ -13,8 +13,8 @@
 // ignore: deprecated_member_use
 import 'package:test_api/test_api.dart' as test_package;
 
-
 import 'binding.dart';
+import 'deprecated.dart';
 
 /// Ensure the [WidgetsBinding] is initialized.
 WidgetsBinding ensureInitialized([@visibleForTesting Map<String, String>? environment]) {
diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart
index 436f27f..8300c59 100644
--- a/packages/flutter_test/lib/src/binding.dart
+++ b/packages/flutter_test/lib/src/binding.dart
@@ -15,8 +15,7 @@
 import 'package:flutter/widgets.dart';
 import 'package:flutter_test/flutter_test.dart' show TestWindow;
 import 'package:stack_trace/stack_trace.dart' as stack_trace;
-// ignore: deprecated_member_use
-import 'package:test_api/test_api.dart' as test_package;
+import 'package:test_api/test_api.dart' as test_package; // ignore: deprecated_member_use
 import 'package:vector_math/vector_math_64.dart';
 
 import '_binding_io.dart' if (dart.library.html) '_binding_web.dart' as binding;
@@ -25,6 +24,7 @@
 import 'restoration.dart';
 import 'stack_manipulation.dart';
 import 'test_async_utils.dart';
+import 'test_default_binary_messenger.dart';
 import 'test_exception_reporter.dart';
 import 'test_text_input.dart';
 
@@ -79,74 +79,29 @@
 
 const Size _kDefaultTestViewportSize = Size(800.0, 600.0);
 
-/// A [BinaryMessenger] subclass that is used as the default binary messenger
-/// under testing environment.
+/// Overrides the [ServicesBinding]'s binary messenger logic to use
+/// [TestDefaultBinaryMessenger].
 ///
-/// It tracks status of data sent across the Flutter platform barrier, which is
-/// useful for testing frameworks to monitor and synchronize against the
-/// platform messages.
-class TestDefaultBinaryMessenger extends BinaryMessenger {
-  /// Creates a [TestDefaultBinaryMessenger] instance.
-  ///
-  /// The [delegate] instance must not be null.
-  TestDefaultBinaryMessenger(this.delegate): assert(delegate != null);
-
-  /// The delegate [BinaryMessenger].
-  final BinaryMessenger delegate;
-
-  final List<Future<ByteData?>> _pendingMessages = <Future<ByteData?>>[];
-
-  /// The number of incomplete/pending calls sent to the platform channels.
-  int get pendingMessageCount => _pendingMessages.length;
-
+/// Test bindings that are used by tests that mock message handlers for plugins
+/// should mix in this binding to enable the use of the
+/// [TestDefaultBinaryMessenger] APIs.
+mixin TestDefaultBinaryMessengerBinding on BindingBase, ServicesBinding {
   @override
-  Future<ByteData?>? send(String channel, ByteData? message) {
-    final Future<ByteData?>? resultFuture = delegate.send(channel, message);
-    if (resultFuture != null) {
-      _pendingMessages.add(resultFuture);
-      resultFuture
-        .catchError((Object error) { /* errors are the responsibility of the caller */ })
-        .whenComplete(() => _pendingMessages.remove(resultFuture));
-    }
-    return resultFuture;
+  void initInstances() {
+    super.initInstances();
+    _instance = this;
   }
 
-  /// Returns a Future that completes after all the platform calls are finished.
-  ///
-  /// If a new platform message is sent after this method is called, this new
-  /// message is not tracked. Use with [pendingMessageCount] to guarantee no
-  /// pending message calls.
-  Future<void> get platformMessagesFinished {
-    return Future.wait<void>(_pendingMessages);
-  }
+  /// The current [TestDefaultBinaryMessengerBinding], if one has been created.
+  static TestDefaultBinaryMessengerBinding? get instance => _instance;
+  static TestDefaultBinaryMessengerBinding? _instance;
 
   @override
-  Future<void> handlePlatformMessage(
-      String channel,
-      ByteData? data,
-      ui.PlatformMessageResponseCallback? callback,
-  ) {
-    return delegate.handlePlatformMessage(channel, data, callback);
-  }
+  TestDefaultBinaryMessenger get defaultBinaryMessenger => super.defaultBinaryMessenger as TestDefaultBinaryMessenger;
 
   @override
-  void setMessageHandler(String channel, MessageHandler? handler) {
-    delegate.setMessageHandler(channel, handler);
-  }
-
-  @override
-  bool checkMessageHandler(String channel, MessageHandler? handler) {
-    return delegate.checkMessageHandler(channel, handler);
-  }
-
-  @override
-  void setMockMessageHandler(String channel, MessageHandler? handler) {
-    delegate.setMockMessageHandler(channel, handler);
-  }
-
-  @override
-  bool checkMockMessageHandler(String channel, MessageHandler? handler) {
-    return delegate.checkMockMessageHandler(channel, handler);
+  TestDefaultBinaryMessenger createBinaryMessenger() {
+    return TestDefaultBinaryMessenger(super.createBinaryMessenger());
   }
 }
 
@@ -171,7 +126,8 @@
        SemanticsBinding,
        RendererBinding,
        PaintingBinding,
-       WidgetsBinding {
+       WidgetsBinding,
+       TestDefaultBinaryMessengerBinding {
 
   /// Constructor for [TestWidgetsFlutterBinding].
   ///
@@ -195,9 +151,15 @@
 
   /// Called by the test framework at the beginning of a widget test to
   /// prepare the binding for the next test.
+  ///
+  /// If [registerTestTextInput] returns true when this method is called,
+  /// the [testTextInput] is configured to simulate the keyboard.
   void reset() {
     _restorationManager = null;
     resetGestureBinding();
+    testTextInput.reset();
+    if (registerTestTextInput)
+      _testTextInput.register();
   }
 
   @override
@@ -237,7 +199,8 @@
   @protected
   bool get overrideHttpClient => true;
 
-  /// Determines whether the binding automatically registers [testTextInput].
+  /// Determines whether the binding automatically registers [testTextInput] as
+  /// a fake keyboard implementation.
   ///
   /// Unit tests make use of this to mock out text input communication for
   /// widgets. An integration test would set this to false, to test real IME
@@ -245,6 +208,19 @@
   ///
   /// [TestTextInput.isRegistered] reports whether the text input mock is
   /// registered or not.
+  ///
+  /// Some of the properties and methods on [testTextInput] are only valid if
+  /// [registerTestTextInput] returns true when a test starts. If those
+  /// members are accessed when using a binding that sets this flag to false,
+  /// they will throw.
+  ///
+  /// If this property returns true when a test ends, the [testTextInput] is
+  /// unregistered.
+  ///
+  /// This property should not change the value it returns during the lifetime
+  /// of the binding. Changing the value of this property risks very confusing
+  /// behavior as the [TestTextInput] may be inconsistently registered or
+  /// unregistered.
   @protected
   bool get registerTestTextInput => true;
 
@@ -319,14 +295,6 @@
       binding.setupHttpOverrides();
     }
     _testTextInput = TestTextInput(onCleared: _resetFocusedEditable);
-    if (registerTestTextInput) {
-      _testTextInput.register();
-    }
-  }
-
-  @override
-  BinaryMessenger createBinaryMessenger() {
-    return TestDefaultBinaryMessenger(super.createBinaryMessenger());
   }
 
   @override
@@ -515,12 +483,20 @@
   TestTextInput get testTextInput => _testTextInput;
   late TestTextInput _testTextInput;
 
-  /// The current client of the onscreen keyboard. Callers must pump
-  /// an additional frame after setting this property to complete the
-  /// focus change.
+  /// The [State] of the current [EditableText] client of the onscreen keyboard.
+  ///
+  /// Setting this property to a new value causes the given [EditableTextState]
+  /// to focus itself and request the keyboard to establish a
+  /// [TextInputConnection].
+  ///
+  /// Callers must pump an additional frame after setting this property to
+  /// complete the focus change.
   ///
   /// Instead of setting this directly, consider using
   /// [WidgetTester.showKeyboard].
+  //
+  // TODO(ianh): We should just remove this property and move the call to
+  // requestKeyboard to the WidgetTester.showKeyboard method.
   EditableTextState? get focusedEditable => _focusedEditable;
   EditableTextState? _focusedEditable;
   set focusedEditable(EditableTextState? value) {
@@ -799,6 +775,8 @@
       // alone so that we don't cause more spurious errors.
       runApp(Container(key: UniqueKey(), child: _postTestMessage)); // Unmount any remaining widgets.
       await pump();
+      if (registerTestTextInput)
+        _testTextInput.unregister();
       invariantTester();
       _verifyAutoUpdateGoldensUnset(autoUpdateGoldensBeforeTest && !isBrowser);
       _verifyReportTestExceptionUnset(reportTestExceptionBeforeTest);
diff --git a/packages/flutter_test/lib/src/deprecated.dart b/packages/flutter_test/lib/src/deprecated.dart
new file mode 100644
index 0000000..b1e1d63
--- /dev/null
+++ b/packages/flutter_test/lib/src/deprecated.dart
@@ -0,0 +1,109 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/services.dart';
+
+import 'binding.dart';
+
+// TODO(ianh): Once https://github.com/dart-lang/dartdoc/issues/2033 is fixed, update the hyperlinks marked HYPERLINK below.
+// TODO(ianh): Once cocoon and other customer_tests are migrated, deprecate these transitional APIs
+
+/// Shim to support the obsolete [setMockMessageHandler] and
+/// [checkMockMessageHandler] methods on [BinaryMessenger] in tests.
+///
+/// The implementations defer to [TestDefaultBinaryMessengerBinding.defaultBinaryMessenger].
+///
+/// Rather than calling [setMockMessageHandler] on the
+/// `ServicesBinding.defaultBinaryMessenger`, use
+/// `tester.binding.defaultBinaryMessenger.setMockMessageHandler` directly. This
+/// more accurately represents the actual method invocation.
+extension TestBinaryMessengerExtension on BinaryMessenger {
+  /// Shim for `TestDefaultBinaryMessenger.setMockMessageHandler`.
+  // HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // TODO(ianh): deprecate this method: @NotYetDeprecated(
+  //   'Use tester.binding.defaultBinaryMessenger.setMockMessageHandler or '
+  //   'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.setMockMessageHandler instead. '
+  //   'This feature was deprecated after v2.1.0-10.0.pre.'
+  // )
+  void setMockMessageHandler(String channel, MessageHandler? handler) {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMessageHandler(channel, handler);
+  }
+
+  /// Shim for `TestDefaultBinaryMessenger.checkMockMessageHandler`.
+  // HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // TODO(ianh): deprecate this method: @NotYetDeprecated(
+  //   'Use tester.binding.defaultBinaryMessenger.checkMockMessageHandler or '
+  //   'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.checkMockMessageHandler instead.'
+  //   'This feature was deprecated after v2.1.0-10.0.pre.'
+  // )
+  bool checkMockMessageHandler(String channel, Object? handler) {
+    return TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(channel, handler);
+  }
+}
+
+/// Shim to support the obsolete [setMockMessageHandler] and
+/// [checkMockMessageHandler] methods on [BasicMessageChannel] in tests.
+///
+/// The implementations defer to [TestDefaultBinaryMessengerBinding.defaultBinaryMessenger].
+///
+/// Rather than calling [setMockMessageHandler] on the message channel, use
+/// `tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler`
+/// directly. This more accurately represents the actual method invocation.
+extension TestBasicMessageChannelExtension<T> on BasicMessageChannel<T> {
+  /// Shim for `TestDefaultBinaryMessenger.setMockDecodedMessageHandler`.
+  // HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // TODO(ianh): deprecate this method: @NotYetDeprecated(
+  //   'Use tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler or '
+  //   'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.setMockDecodedMessageHandler instead. '
+  //   'This feature was deprecated after v2.1.0-10.0.pre.'
+  // )
+  void setMockMessageHandler(Future<T> Function(T? message)? handler) {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockDecodedMessageHandler<T>(this, handler);
+  }
+
+  /// Shim for `TestDefaultBinaryMessenger.checkMockMessageHandler`.
+  // HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // TODO(ianh): deprecate this method: @NotYetDeprecated(
+  //   'Use tester.binding.defaultBinaryMessenger.checkMockMessageHandler or '
+  //   'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.checkMockMessageHandler instead. '
+  //   'For the first argument, pass channel.name. '
+  //   'This feature was deprecated after v2.1.0-10.0.pre.'
+  // )
+  bool checkMockMessageHandler(Object? handler) {
+    return TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(name, handler);
+  }
+}
+
+/// Shim to support the obsolete [setMockMethodCallHandler] and
+/// [checkMockMethodCallHandler] methods on [MethodChannel] in tests.
+///
+/// The implementations defer to [TestDefaultBinaryMessengerBinding.defaultBinaryMessenger].
+///
+/// Rather than calling [setMockMethodCallHandler] on the method channel, use
+/// `tester.binding.defaultBinaryMessenger.setMockMethodCallHandler` directly.
+/// This more accurately represents the actual method invocation.
+extension TestMethodChannelExtension on MethodChannel {
+  /// Shim for `TestDefaultBinaryMessenger.setMockMethodCallHandler`.
+  // HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // TODO(ianh): deprecate this method: @NotYetDeprecated(
+  //   'Use tester.binding.defaultBinaryMessenger.setMockMethodCallHandler or '
+  //   'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.setMockMethodCallHandler instead. '
+  //   'This feature was deprecated after v2.1.0-10.0.pre.'
+  // )
+  void setMockMethodCallHandler(Future<dynamic>? Function(MethodCall call)? handler) {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.setMockMethodCallHandler(this, handler);
+  }
+
+  /// Shim for `TestDefaultBinaryMessenger.checkMockMessageHandler`.
+  // HYPERLINK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // TODO(ianh): deprecate this method: @NotYetDeprecated(
+  //   'Use tester.binding.defaultBinaryMessenger.checkMockMessageHandler or '
+  //   'TestDefaultBinaryMessenger.instance.defaultBinaryMessenger.checkMockMessageHandler instead. '
+  //   'For the first argument, pass channel.name. '
+  //   'This feature was deprecated after v2.1.0-10.0.pre.'
+  // )
+  bool checkMockMethodCallHandler(Object? handler) {
+    return TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.checkMockMessageHandler(name, handler);
+  }
+}
diff --git a/packages/flutter_test/lib/src/event_simulation.dart b/packages/flutter_test/lib/src/event_simulation.dart
index ce9504b..e8d81a0 100644
--- a/packages/flutter_test/lib/src/event_simulation.dart
+++ b/packages/flutter_test/lib/src/event_simulation.dart
@@ -2,10 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'dart:async';
 import 'dart:io';
 
 import 'package:flutter/foundation.dart' show kIsWeb;
 import 'package:flutter/services.dart';
+
+import 'binding.dart';
 import 'test_async_utils.dart';
 
 // TODO(gspencergoog): Replace this with more robust key simulation code once
@@ -640,22 +643,22 @@
       platform ??= Platform.operatingSystem;
       assert(_osIsSupported(platform!), 'Platform $platform not supported for key simulation');
 
+
       final Map<String, dynamic> data = getKeyData(key, platform: platform!, isDown: true, physicalKey: physicalKey, character: character);
-      bool result = false;
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      final Completer<bool> result = Completer<bool>();
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
         (ByteData? data) {
           if (data == null) {
+            result.complete(false);
             return;
           }
           final Map<String, dynamic> decoded = SystemChannels.keyEvent.codec.decodeMessage(data) as Map<String, dynamic>;
-          if (decoded['handled'] as bool) {
-            result = true;
-          }
+          result.complete(decoded['handled'] as bool);
         }
       );
-      return result;
+      return result.future;
     });
   }
 
@@ -681,7 +684,7 @@
 
       final Map<String, dynamic> data = getKeyData(key, platform: platform!, isDown: false, physicalKey: physicalKey);
       bool result = false;
-      await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      await TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.keyEvent.name,
         SystemChannels.keyEvent.codec.encodeMessage(data),
         (ByteData? data) {
diff --git a/packages/flutter_test/lib/src/test_default_binary_messenger.dart b/packages/flutter_test/lib/src/test_default_binary_messenger.dart
new file mode 100644
index 0000000..d0e18ac
--- /dev/null
+++ b/packages/flutter_test/lib/src/test_default_binary_messenger.dart
@@ -0,0 +1,306 @@
+// Copyright 2014 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:ui' as ui;
+
+import 'package:fake_async/fake_async.dart';
+import 'package:flutter/services.dart';
+
+/// A [BinaryMessenger] subclass that is used as the default binary messenger
+/// under testing environment.
+///
+/// It tracks status of data sent across the Flutter platform barrier, which is
+/// useful for testing frameworks to monitor and synchronize against the
+/// platform messages.
+///
+/// ## Messages from the framework to the platform
+///
+/// Messages are sent from the framework to the platform via the
+/// [send] method.
+///
+/// To intercept a message sent from the framework to the platform,
+/// consider using [setMockMessageHandler],
+/// [setMockDecodedMessageHandler], and [setMockMethodCallHandler]
+/// (see also [checkMockMessageHandler]).
+///
+/// To wait for all pending framework-to-platform messages, the
+/// [platformMessagesFinished] getter provides an appropriate
+/// [Future]. The [pendingMessageCount] getter returns the current
+/// number of outstanding messages.
+///
+/// ## Messages from the platform to the framework
+///
+/// The platform sends messages via the [ChannelBuffers] API. Mock
+/// messages can be sent to the framework using
+/// [handlePlatformMessage].
+///
+/// Listeners for these messages are configured using [setMessageHandler].
+class TestDefaultBinaryMessenger extends BinaryMessenger {
+  /// Creates a [TestDefaultBinaryMessenger] instance.
+  ///
+  /// The [delegate] instance must not be null.
+  TestDefaultBinaryMessenger(this.delegate): assert(delegate != null);
+
+  /// The delegate [BinaryMessenger].
+  final BinaryMessenger delegate;
+
+  // The handlers for messages from the engine (including fake
+  // messages sent by handlePlatformMessage).
+  final Map<String, MessageHandler> _inboundHandlers = <String, MessageHandler>{};
+
+  /// Send a mock message to the framework as if it came from the platform.
+  ///
+  /// If a listener has been set using [setMessageHandler], that listener is
+  /// invoked to handle the message, and this method returns a future that
+  /// completes with that handler's result.
+  ///
+  /// {@template flutter.flutter_test.TestDefaultBinaryMessenger.handlePlatformMessage.asyncHandlers}
+  /// It is strongly recommended that all handlers used with this API be
+  /// synchronous (not requiring any microtasks to complete), because
+  /// [testWidgets] tests run in a [FakeAsync] zone in which microtasks do not
+  /// progress except when time is explicitly advanced (e.g. with
+  /// [WidgetTester.pump]), which means that `await`ing a [Future] will result
+  /// in the test hanging.
+  /// {@endtemplate}
+  ///
+  /// If no listener is configured, this method returns right away with null.
+  ///
+  /// The `callback` argument, if non-null, will be called just before this
+  /// method's future completes, either with the result of the listener
+  /// registered with [setMessageHandler], or with null if no listener has
+  /// been registered.
+  ///
+  /// Messages can also be sent via [ChannelBuffers.push] (see
+  /// [ServicesBinding.channelBuffers]); the effect is the same, though that API
+  /// will not wait for a response.
+  // TODO(ianh): When the superclass `handlePlatformMessage` is removed,
+  // remove this @override (but leave the method).
+  @override
+  Future<ByteData?> handlePlatformMessage(
+    String channel,
+    ByteData? data,
+    ui.PlatformMessageResponseCallback? callback,
+  ) {
+    Future<ByteData?>? result;
+    if (_inboundHandlers.containsKey(channel))
+      result = _inboundHandlers[channel]!(data);
+    result ??= Future<ByteData?>.value(null);
+    if (callback != null)
+      result = result.then((ByteData? result) { callback(result); return result; });
+    return result;
+  }
+
+  @override
+  void setMessageHandler(String channel, MessageHandler? handler) {
+    if (handler == null) {
+      _inboundHandlers.remove(channel);
+      delegate.setMessageHandler(channel, null);
+    } else {
+      _inboundHandlers[channel] = handler; // used to handle fake messages sent via handlePlatformMessage
+      delegate.setMessageHandler(channel, handler); // used to handle real messages from the engine
+    }
+  }
+
+  final List<Future<ByteData?>> _pendingMessages = <Future<ByteData?>>[];
+
+  /// The number of incomplete/pending calls sent to the platform channels.
+  int get pendingMessageCount => _pendingMessages.length;
+
+  // Handlers that intercept and respond to outgoing messages,
+  // pretending to be the platform.
+  final Map<String, MessageHandler> _outboundHandlers = <String, MessageHandler>{};
+
+  // The outbound callbacks that were actually registered, so that we
+  // can implement the [checkMockMessageHandler] method.
+  final Map<String, Object> _outboundHandlerIdentities = <String, Object>{};
+
+  @override
+  Future<ByteData?>? send(String channel, ByteData? message) {
+    final Future<ByteData?>? resultFuture;
+    final MessageHandler? handler = _outboundHandlers[channel];
+    if (handler != null) {
+      resultFuture = handler(message);
+    } else {
+      resultFuture = delegate.send(channel, message);
+    }
+    if (resultFuture != null) {
+      _pendingMessages.add(resultFuture);
+      resultFuture
+        .catchError((Object error) { /* errors are the responsibility of the caller */ })
+        .whenComplete(() => _pendingMessages.remove(resultFuture));
+    }
+    return resultFuture;
+  }
+
+  /// Returns a Future that completes after all the platform calls are finished.
+  ///
+  /// If a new platform message is sent after this method is called, this new
+  /// message is not tracked. Use with [pendingMessageCount] to guarantee no
+  /// pending message calls.
+  Future<void> get platformMessagesFinished {
+    return Future.wait<void>(_pendingMessages);
+  }
+
+  /// Set a callback for intercepting messages sent to the platform on
+  /// the given channel, without decoding them.
+  ///
+  /// Intercepted messages are not forwarded to the platform.
+  ///
+  /// The given callback will replace the currently registered
+  /// callback for that channel, if any. To stop intercepting messages
+  /// at all, pass null as the handler.
+  ///
+  /// The handler's return value, if non-null, is used as a response,
+  /// unencoded.
+  ///
+  /// {@macro flutter.flutter_test.TestDefaultBinaryMessenger.handlePlatformMessage.asyncHandlers}
+  ///
+  /// The `identity` argument, if non-null, is used to identify the
+  /// callback when checked by [checkMockMessageHandler]. If null, the
+  /// `handler` is used instead. (This allows closures to be passed as
+  /// the `handler` with an alias used as the `identity` so that a
+  /// reference to the closure need not be used. In practice, this is
+  /// used by [setMockDecodedMessageHandler] and
+  /// [setMockMethodCallHandler] to allow [checkMockMessageHandler] to
+  /// recognize the closures that were passed to those methods even
+  /// though those methods wrap those closures when passing them to
+  /// this method.)
+  ///
+  /// Registered callbacks are cleared after each test.
+  ///
+  /// See also:
+  ///
+  ///  * [checkMockMessageHandler], which can verify if a handler is still
+  ///    registered, which is useful in tests to ensure that no unexpected
+  ///    handlers are being registered.
+  ///
+  ///  * [setMockDecodedMessageHandler], which wraps this method but
+  ///    decodes the messages using a [MessageCodec].
+  ///
+  ///  * [setMockMethodCallHandler], which wraps this method but decodes
+  ///    the messages using a [MethodCodec].
+  void setMockMessageHandler(String channel, MessageHandler? handler, [ Object? identity ]) {
+    if (handler == null) {
+      _outboundHandlers.remove(channel);
+      _outboundHandlerIdentities.remove(channel);
+    } else {
+      identity ??= handler;
+      _outboundHandlers[channel] = handler;
+      _outboundHandlerIdentities[channel] = identity;
+    }
+  }
+
+  /// Set a callback for intercepting messages sent to the platform on
+  /// the given channel.
+  ///
+  /// Intercepted messages are not forwarded to the platform.
+  ///
+  /// The given callback will replace the currently registered
+  /// callback for that channel, if any. To stop intercepting messages
+  /// at all, pass null as the handler.
+  ///
+  /// Messages are decoded using the codec of the channel.
+  ///
+  /// The handler's return value, if non-null, is used as a response,
+  /// after encoding it using the channel's codec.
+  ///
+  /// {@macro flutter.flutter_test.TestDefaultBinaryMessenger.handlePlatformMessage.asyncHandlers}
+  ///
+  /// Registered callbacks are cleared after each test.
+  ///
+  /// See also:
+  ///
+  ///  * [checkMockMessageHandler], which can verify if a handler is still
+  ///    registered, which is useful in tests to ensure that no unexpected
+  ///    handlers are being registered.
+  ///
+  ///  * [setMockMessageHandler], which is similar but provides raw
+  ///    access to the underlying bytes.
+  ///
+  ///  * [setMockMethodCallHandler], which is similar but decodes
+  ///    the messages using a [MethodCodec].
+  void setMockDecodedMessageHandler<T>(BasicMessageChannel<T> channel, Future<T> Function(T? message)? handler) {
+    if (handler == null) {
+      setMockMessageHandler(channel.name, null);
+      return;
+    }
+    setMockMessageHandler(channel.name, (ByteData? message) async {
+      return channel.codec.encodeMessage(await handler(channel.codec.decodeMessage(message)));
+    }, handler);
+  }
+
+  /// Set a callback for intercepting method calls sent to the
+  /// platform on the given channel.
+  ///
+  /// Intercepted method calls are not forwarded to the platform.
+  ///
+  /// The given callback will replace the currently registered
+  /// callback for that channel, if any. To stop intercepting messages
+  /// at all, pass null as the handler.
+  ///
+  /// Methods are decoded using the codec of the channel.
+  ///
+  /// The handler's return value, if non-null, is used as a response,
+  /// after re-encoding it using the channel's codec.
+  ///
+  /// To send an error, throw a [PlatformException] in the handler.
+  /// Other exceptions are not caught.
+  ///
+  /// {@macro flutter.flutter_test.TestDefaultBinaryMessenger.handlePlatformMessage.asyncHandlers}
+  ///
+  /// Registered callbacks are cleared after each test.
+  ///
+  /// See also:
+  ///
+  ///  * [checkMockMessageHandler], which can verify if a handler is still
+  ///    registered, which is useful in tests to ensure that no unexpected
+  ///    handlers are being registered.
+  ///
+  ///  * [setMockMessageHandler], which is similar but provides raw
+  ///    access to the underlying bytes.
+  ///
+  ///  * [setMockDecodedMessageHandler], which is similar but decodes
+  ///    the messages using a [MessageCodec].
+  void setMockMethodCallHandler(MethodChannel channel, Future<Object?>? Function(MethodCall message)? handler) {
+    if (handler == null) {
+      setMockMessageHandler(channel.name, null);
+      return;
+    }
+    setMockMessageHandler(channel.name, (ByteData? message) async {
+      final MethodCall call = channel.codec.decodeMethodCall(message);
+      try {
+        return channel.codec.encodeSuccessEnvelope(await handler(call));
+      } on PlatformException catch (error) {
+        return channel.codec.encodeErrorEnvelope(
+          code: error.code,
+          message: error.message,
+          details: error.details,
+        );
+      } on MissingPluginException {
+        return null;
+      } catch (error) {
+        return channel.codec.encodeErrorEnvelope(code: 'error', message: '$error', details: null);
+      }
+    }, handler);
+  }
+
+  /// Returns true if the `handler` argument matches the `handler`
+  /// previously passed to [setMockMessageHandler],
+  /// [setMockDecodedMessageHandler], or [setMockMethodCallHandler].
+  ///
+  /// Specifically, it compares the argument provided to the `identity`
+  /// argument provided to [setMockMessageHandler], defaulting to the
+  /// `handler` argument passed to that method is `identity` was null.
+  ///
+  /// This method is useful for tests or test harnesses that want to assert the
+  /// mock handler for the specified channel has not been altered by a previous
+  /// test.
+  ///
+  /// Passing null for the `handler` returns true if the handler for the
+  /// `channel` is not set.
+  ///
+  /// Registered callbacks are cleared after each test.
+  bool checkMockMessageHandler(String channel, Object? handler) => _outboundHandlerIdentities[channel] == handler;
+}
diff --git a/packages/flutter_test/lib/src/test_text_input.dart b/packages/flutter_test/lib/src/test_text_input.dart
index c20fd56..a99bcef 100644
--- a/packages/flutter_test/lib/src/test_text_input.dart
+++ b/packages/flutter_test/lib/src/test_text_input.dart
@@ -8,12 +8,28 @@
 import 'package:flutter/services.dart';
 import 'package:flutter_test/flutter_test.dart';
 
+import 'binding.dart' show TestDefaultBinaryMessengerBinding;
+import 'deprecated.dart';
+import 'test_async_utils.dart';
+
 export 'package:flutter/services.dart' show TextEditingValue, TextInputAction;
 
 /// A testing stub for the system's onscreen keyboard.
 ///
 /// Typical app tests will not need to use this class directly.
 ///
+/// The [TestWidgetsFlutterBinding] class registers a [TestTextInput] instance
+/// ([TestWidgetsFlutterBinding.testTextInput]) as a stub keyboard
+/// implementation if its [TestWidgetsFlutterBinding.registerTestTextInput]
+/// property returns true when a test starts, and unregisters it when the test
+/// ends (unless it ends with a failure).
+///
+/// See [register], [unregister], and [isRegistered] for details.
+///
+/// The [enterText], [updateEditingValue], [receiveAction], and
+/// [closeConnection] methods can be used even when the [TestTextInput] is not
+/// registered. All other methods will assert if [isRegistered] is false.
+///
 /// See also:
 ///
 /// * [WidgetTester.enterText], which uses this class to simulate keyboard input.
@@ -33,61 +49,76 @@
   /// first be requested, e.g. using [WidgetTester.showKeyboard].
   final VoidCallback? onCleared;
 
-  /// The messenger which sends the bytes for this channel, not null.
-  BinaryMessenger get _binaryMessenger => ServicesBinding.instance!.defaultBinaryMessenger;
-
-  /// Resets any internal state of this object and calls [register].
-  ///
-  /// This method is invoked by the testing framework between tests. It should
-  /// not ordinarily be called by tests directly.
-  void resetAndRegister() {
-    log.clear();
-    editingState = null;
-    setClientArgs = null;
-    _client = 0;
-    _isVisible = false;
-    register();
-  }
-  /// Installs this object as a mock handler for [SystemChannels.textInput].
-  void register() => SystemChannels.textInput.setMockMethodCallHandler(_handleTextInputCall);
-
-  /// Removes this object as a mock handler for [SystemChannels.textInput].
-  ///
-  /// After calling this method, the channel will exchange messages with the
-  /// Flutter engine. Use this with [FlutterDriver] tests that need to display
-  /// on-screen keyboard provided by the operating system.
-  void unregister() => SystemChannels.textInput.setMockMethodCallHandler(null);
-
   /// Log for method calls.
   ///
   /// For all registered channels, handled calls are added to the list. Can
   /// be cleaned using `log.clear()`.
   final List<MethodCall> log = <MethodCall>[];
 
+  /// Installs this object as a mock handler for [SystemChannels.textInput].
+  ///
+  /// Called by the binding at the top of a test when
+  /// [TestWidgetsFlutterBinding.registerTestTextInput] is true.
+  void register() => SystemChannels.textInput.setMockMethodCallHandler(_handleTextInputCall);
+
+  /// Removes this object as a mock handler for [SystemChannels.textInput].
+  ///
+  /// After calling this method, the channel will exchange messages with the
+  /// Flutter engine instead of the stub.
+  ///
+  /// Called by the binding at the end of a (successful) test when
+  /// [TestWidgetsFlutterBinding.registerTestTextInput] is true.
+  void unregister() => SystemChannels.textInput.setMockMethodCallHandler(null);
+
   /// Whether this [TestTextInput] is registered with [SystemChannels.textInput].
   ///
-  /// Use [register] and [unregister] methods to control this value.
+  /// The binding uses the [register] and [unregister] methods to control this
+  /// value when [TestWidgetsFlutterBinding.registerTestTextInput] is true.
   bool get isRegistered => SystemChannels.textInput.checkMockMethodCallHandler(_handleTextInputCall);
 
+  int? _client;
+
   /// Whether there are any active clients listening to text input.
   bool get hasAnyClients {
     assert(isRegistered);
-    return _client > 0;
+    return _client != null && _client! > 0;
   }
 
-  int _client = 0;
-
-  /// Arguments supplied to the TextInput.setClient method call.
+  /// The last set of arguments supplied to the `TextInput.setClient` and
+  /// `TextInput.updateConfig` methods of this stub implementation.
   Map<String, dynamic>? setClientArgs;
 
   /// The last set of arguments that [TextInputConnection.setEditingState] sent
-  /// to the embedder.
+  /// to this stub implementation (i.e. the arguments set to
+  /// `TextInput.setEditingState`).
   ///
   /// This is a map representation of a [TextEditingValue] object. For example,
   /// it will have a `text` entry whose value matches the most recent
   /// [TextEditingValue.text] that was sent to the embedder.
   Map<String, dynamic>? editingState;
 
+  /// Whether the onscreen keyboard is visible to the user.
+  ///
+  /// Specifically, this reflects the last call to `TextInput.show` or
+  /// `TextInput.hide` received by the stub implementation.
+  bool get isVisible {
+    assert(isRegistered);
+    return _isVisible;
+  }
+  bool _isVisible = false;
+
+  /// Resets any internal state of this object.
+  ///
+  /// This method is invoked by the testing framework between tests. It should
+  /// not ordinarily be called by tests directly.
+  void reset() {
+    log.clear();
+    _client = null;
+    setClientArgs = null;
+    editingState = null;
+    _isVisible = false;
+  }
+
   Future<dynamic> _handleTextInputCall(MethodCall methodCall) async {
     log.add(methodCall);
     switch (methodCall.method) {
@@ -99,7 +130,7 @@
         setClientArgs = methodCall.arguments as Map<String, dynamic>;
         break;
       case 'TextInput.clearClient':
-        _client = 0;
+        _client = null;
         _isVisible = false;
         onCleared?.call();
         break;
@@ -115,87 +146,86 @@
     }
   }
 
-  /// Whether the onscreen keyboard is visible to the user.
-  bool get isVisible {
-    assert(isRegistered);
-    return _isVisible;
-  }
-  bool _isVisible = false;
-
-  /// Simulates the user changing the [TextEditingValue] to the given value.
-  void updateEditingValue(TextEditingValue value) {
-    assert(isRegistered);
-    // Not using the `expect` function because in the case of a FlutterDriver
-    // test this code does not run in a package:test test zone.
-    if (_client == 0)
-      throw TestFailure('Tried to use TestTextInput with no keyboard attached. You must use WidgetTester.showKeyboard() first.');
-    _binaryMessenger.handlePlatformMessage(
-      SystemChannels.textInput.name,
-      SystemChannels.textInput.codec.encodeMethodCall(
-        MethodCall(
-          'TextInputClient.updateEditingState',
-          <dynamic>[_client, value.toJSON()],
-        ),
-      ),
-      (ByteData? data) { /* response from framework is discarded */ },
-    );
-  }
-
-  /// Simulates the user closing the text input connection.
+  /// Simulates the user hiding the onscreen keyboard.
   ///
-  /// For example:
-  /// - User pressed the home button and sent the application to background.
-  /// - User closed the virtual keyboard.
-  void closeConnection() {
+  /// This does nothing but set the internal flag.
+  void hide() {
     assert(isRegistered);
-    // Not using the `expect` function because in the case of a FlutterDriver
-    // test this code does not run in a package:test test zone.
-    if (_client == 0)
-      throw TestFailure('Tried to use TestTextInput with no keyboard attached. You must use WidgetTester.showKeyboard() first.');
-    _binaryMessenger.handlePlatformMessage(
-      SystemChannels.textInput.name,
-      SystemChannels.textInput.codec.encodeMethodCall(
-        MethodCall(
-          'TextInputClient.onConnectionClosed',
-           <dynamic>[_client,]
-        ),
-      ),
-      (ByteData? data) { /* response from framework is discarded */ },
-    );
+    _isVisible = false;
   }
 
-  /// Simulates the user typing the given text.
+  /// Simulates the user changing the text of the focused text field, and resets
+  /// the selection.
   ///
   /// Calling this method replaces the content of the connected input field with
   /// `text`, and places the caret at the end of the text.
+  ///
+  /// To update the UI under test after this method is invoked, use
+  /// [WidgetTester.pump].
+  ///
+  /// This can be called even if the [TestTextInput] has not been [register]ed.
+  ///
+  /// If this is used to inject text when there is a real IME connection, for
+  /// example when using the [integration_test] library, there is a risk that
+  /// the real IME will become confused as to the current state of input.
+  ///
+  /// See also:
+  ///
+  ///  * [updateEditingValue], which takes a [TextEditingValue] so that one can
+  ///    also change the selection.
   void enterText(String text) {
-    assert(isRegistered);
     updateEditingValue(TextEditingValue(
       text: text,
       selection: TextSelection.collapsed(offset: text.length),
     ));
   }
 
+  /// Simulates the user changing the [TextEditingValue] to the given value.
+  ///
+  /// To update the UI under test after this method is invoked, use
+  /// [WidgetTester.pump].
+  ///
+  /// This can be called even if the [TestTextInput] has not been [register]ed.
+  ///
+  /// If this is used to inject text when there is a real IME connection, for
+  /// example when using the [integration_test] library, there is a risk that
+  /// the real IME will become confused as to the current state of input.
+  ///
+  /// See also:
+  ///
+  ///  * [enterText], which is similar but takes only a String and resets the
+  ///    selection.
+  void updateEditingValue(TextEditingValue value) {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      SystemChannels.textInput.name,
+      SystemChannels.textInput.codec.encodeMethodCall(
+        MethodCall(
+          'TextInputClient.updateEditingState',
+          <dynamic>[_client ?? -1, value.toJSON()],
+        ),
+      ),
+      (ByteData? data) { /* ignored */ },
+    );
+  }
+
   /// Simulates the user pressing one of the [TextInputAction] buttons.
   /// Does not check that the [TextInputAction] performed is an acceptable one
   /// based on the `inputAction` [setClientArgs].
+  ///
+  /// This can be called even if the [TestTextInput] has not been [register]ed.
+  ///
+  /// If this is used to inject an action when there is a real IME connection,
+  /// for example when using the [integration_test] library, there is a risk
+  /// that the real IME will become confused as to the current state of input.
   Future<void> receiveAction(TextInputAction action) async {
-    assert(isRegistered);
     return TestAsyncUtils.guard(() {
-      // Not using the `expect` function because in the case of a FlutterDriver
-      // test this code does not run in a package:test test zone.
-      if (_client == 0) {
-        throw TestFailure('Tried to use TestTextInput with no keyboard attached. You must use WidgetTester.showKeyboard() first.');
-      }
-
       final Completer<void> completer = Completer<void>();
-
-      _binaryMessenger.handlePlatformMessage(
+      TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
         SystemChannels.textInput.name,
         SystemChannels.textInput.codec.encodeMethodCall(
           MethodCall(
             'TextInputClient.performAction',
-            <dynamic>[_client, action.toString()],
+            <dynamic>[_client ?? -1, action.toString()],
           ),
         ),
         (ByteData? data) {
@@ -204,8 +234,7 @@
             // Decoding throws a PlatformException if the data represents an
             // error, and that's all we care about here.
             SystemChannels.textInput.codec.decodeEnvelope(data!);
-
-            // No error was found. Complete without issue.
+            // If we reach here then no error was found. Complete without issue.
             completer.complete();
           } catch (error) {
             // An exception occurred as a result of receiveAction()'ing. Report
@@ -214,14 +243,32 @@
           }
         },
       );
-
       return completer.future;
     });
   }
 
-  /// Simulates the user hiding the onscreen keyboard.
-  void hide() {
-    assert(isRegistered);
-    _isVisible = false;
+  /// Simulates the user closing the text input connection.
+  ///
+  /// For example:
+  ///
+  ///  * User pressed the home button and sent the application to background.
+  ///  * User closed the virtual keyboard.
+  ///
+  /// This can be called even if the [TestTextInput] has not been [register]ed.
+  ///
+  /// If this is used to inject text when there is a real IME connection, for
+  /// example when using the [integration_test] library, there is a risk that
+  /// the real IME will become confused as to the current state of input.
+  void closeConnection() {
+    TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger.handlePlatformMessage(
+      SystemChannels.textInput.name,
+      SystemChannels.textInput.codec.encodeMethodCall(
+        MethodCall(
+          'TextInputClient.onConnectionClosed',
+           <dynamic>[_client ?? -1],
+        ),
+      ),
+      (ByteData? data) { /* response from framework is discarded */ },
+    );
   }
 }
diff --git a/packages/flutter_test/lib/src/widget_tester.dart b/packages/flutter_test/lib/src/widget_tester.dart
index 4e9c7ab..80e993b 100644
--- a/packages/flutter_test/lib/src/widget_tester.dart
+++ b/packages/flutter_test/lib/src/widget_tester.dart
@@ -129,7 +129,7 @@
   dynamic tags,
 }) {
   assert(variant != null);
-  assert(variant.values.isNotEmpty, 'There must be at least on value to test in the testing variant');
+  assert(variant.values.isNotEmpty, 'There must be at least one value to test in the testing variant.');
   final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
   final WidgetTester tester = WidgetTester._(binding);
   for (final dynamic value in variant.values) {
@@ -147,9 +147,8 @@
         test_package.addTearDown(binding.postTest);
         return binding.runTest(
           () async {
-            binding.reset();
+            binding.reset(); // TODO(ianh): the binding should just do this itself in _runTest
             debugResetSemanticsIdCounter();
-            tester.resetTestTextInput();
             Object? memento;
             try {
               memento = await variant.setUp(value);
@@ -918,10 +917,12 @@
   /// Acts as if the application went idle.
   ///
   /// Runs all remaining microtasks, including those scheduled as a result of
-  /// running them, until there are no more microtasks scheduled.
+  /// running them, until there are no more microtasks scheduled. Then, runs any
+  /// previously scheduled timers with zero time, and completes the returned future.
   ///
-  /// Does not run timers. May result in an infinite loop or run out of memory
-  /// if microtasks continue to recursively schedule new microtasks.
+  /// May result in an infinite loop or run out of memory if microtasks continue
+  /// to recursively schedule new microtasks. Will not run any timers scheduled
+  /// after this method was invoked, even if they are zero-time timers.
   Future<void> idle() {
     return TestAsyncUtils.guard<void>(() => binding.idle());
   }
@@ -1002,18 +1003,13 @@
   ///
   /// Typical app tests will not need to use this value. To add text to widgets
   /// like [TextField] or [TextFormField], call [enterText].
-  TestTextInput get testTextInput => binding.testTextInput;
-
-  /// Ensures that [testTextInput] is registered and [TestTextInput.log] is
-  /// reset.
   ///
-  /// This is called by the testing framework before test runs, so that if a
-  /// previous test has set its own handler on [SystemChannels.textInput], the
-  /// [testTextInput] regains control and the log is fresh for the new test.
-  /// It should not typically need to be called by tests.
-  void resetTestTextInput() {
-    testTextInput.resetAndRegister();
-  }
+  /// Some of the properties and methods on this value are only valid if the
+  /// binding's [TestWidgetsFlutterBinding.registerTestTextInput] flag is set to
+  /// true as a test is starting (meaning that the keyboard is to be simulated
+  /// by the test framework). If those members are accessed when using a binding
+  /// that sets this flag to false, they will throw.
+  TestTextInput get testTextInput => binding.testTextInput;
 
   /// Give the text input widget specified by [finder] the focus, as if the
   /// onscreen keyboard had appeared.
@@ -1035,6 +1031,9 @@
           matchRoot: true,
         ),
       );
+      // Setting focusedEditable causes the binding to call requestKeyboard()
+      // on the EditableTextState, which itself eventually calls TextInput.attach
+      // to establish the connection.
       binding.focusedEditable = editable;
       await pump();
     });
@@ -1052,6 +1051,12 @@
   ///
   /// To just give [finder] the focus without entering any text,
   /// see [showKeyboard].
+  ///
+  /// To enter text into other widgets (e.g. a custom widget that maintains a
+  /// TextInputConnection the way that a [EditableText] does), first ensure that
+  /// that widget has an open connection (e.g. by using [tap] to to focus it),
+  /// then call `testTextInput.enterText` directly (see
+  /// [TestTextInput.enterText]).
   Future<void> enterText(Finder finder, String text) async {
     return TestAsyncUtils.guard<void>(() async {
       await showKeyboard(finder);
diff --git a/packages/flutter_test/lib/src/window.dart b/packages/flutter_test/lib/src/window.dart
index 500dd68..c27c57d 100644
--- a/packages/flutter_test/lib/src/window.dart
+++ b/packages/flutter_test/lib/src/window.dart
@@ -379,8 +379,16 @@
     platformDispatcher.sendPlatformMessage(name, data, callback);
   }
 
+  @Deprecated(
+    'Instead of calling this callback, use ServicesBinding.instance.channelBuffers.push. '
+    'This feature was deprecated after v2.1.0-10.0.pre.'
+  )
   @override
   ui.PlatformMessageCallback? get onPlatformMessage => platformDispatcher.onPlatformMessage;
+  @Deprecated(
+    'Instead of setting this callback, use ServicesBinding.instance.defaultBinaryMessenger.setMessageHandler. '
+    'This feature was deprecated after v2.1.0-10.0.pre.'
+  )
   @override
   set onPlatformMessage(ui.PlatformMessageCallback? callback) {
     platformDispatcher.onPlatformMessage = callback;
diff --git a/packages/flutter_test/test/bindings_test.dart b/packages/flutter_test/test/bindings_test.dart
index 15e1431..bc98524 100644
--- a/packages/flutter_test/test/bindings_test.dart
+++ b/packages/flutter_test/test/bindings_test.dart
@@ -11,6 +11,8 @@
 import 'package:test_api/test_api.dart' as test_package;
 
 void main() {
+  final AutomatedTestWidgetsFlutterBinding binding = AutomatedTestWidgetsFlutterBinding();
+
   group(TestViewConfiguration, () {
     test('is initialized with top-level window if one is not provided', () {
       // The code below will throw without the default.
@@ -20,15 +22,32 @@
 
   group(AutomatedTestWidgetsFlutterBinding, () {
     test('allows setting defaultTestTimeout to 5 minutes', () {
-      final AutomatedTestWidgetsFlutterBinding binding = AutomatedTestWidgetsFlutterBinding();
       binding.defaultTestTimeout = const test_package.Timeout(Duration(minutes: 5));
       expect(binding.defaultTestTimeout.duration, const Duration(minutes: 5));
     });
   });
 
+  // The next three tests must run in order -- first using `test`, then `testWidgets`, then `test` again.
+
+  int order = 0;
+
   test('Initializes httpOverrides and testTextInput', () async {
-    final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
-    expect(binding.testTextInput.isRegistered, true);
+    assert(order == 0);
+    expect(binding.testTextInput, isNotNull);
+    expect(binding.testTextInput.isRegistered, isFalse);
     expect(HttpOverrides.current, isNotNull);
+    order += 1;
+  });
+
+  testWidgets('Registers testTextInput', (WidgetTester tester) async {
+    assert(order == 1);
+    expect(tester.testTextInput.isRegistered, isTrue);
+    order += 1;
+  });
+
+  test('Unregisters testTextInput', () async {
+    assert(order == 2);
+    expect(binding.testTextInput.isRegistered, isFalse);
+    order += 1;
   });
 }
diff --git a/packages/flutter_test/test/test_default_binary_messenger_test.dart b/packages/flutter_test/test/test_default_binary_messenger_test.dart
index 82cb18f..30cf93d 100644
--- a/packages/flutter_test/test/test_default_binary_messenger_test.dart
+++ b/packages/flutter_test/test/test_default_binary_messenger_test.dart
@@ -20,12 +20,6 @@
   Future<void> handlePlatformMessage(String channel, ByteData? data, ui.PlatformMessageResponseCallback? callback) => throw UnimplementedError();
   @override
   void setMessageHandler(String channel, MessageHandler? handler) => throw UnimplementedError();
-  @override
-  bool checkMessageHandler(String channel, MessageHandler? handler) => throw UnimplementedError();
-  @override
-  void setMockMessageHandler(String channel, MessageHandler? handler) => throw UnimplementedError();
-  @override
-  bool checkMockMessageHandler(String channel, MessageHandler? handler) => throw UnimplementedError();
 }
 
 void main() {
diff --git a/packages/flutter_web_plugins/lib/src/plugin_registry.dart b/packages/flutter_web_plugins/lib/src/plugin_registry.dart
index ecd273f..cc397b7 100644
--- a/packages/flutter_web_plugins/lib/src/plugin_registry.dart
+++ b/packages/flutter_web_plugins/lib/src/plugin_registry.dart
@@ -61,7 +61,7 @@
   /// the [dart:ui] library. That function is only available when
   /// compiling for the web.
   void registerMessageHandler() {
-    // The function below is only defined in the Web dart:ui.
+    // The `ui.webOnlySetPluginHandler` function below is only defined in the Web dart:ui.
     // ignore: undefined_function
     ui.webOnlySetPluginHandler(handleFrameworkMessage);
   }
@@ -141,7 +141,7 @@
   @override
   Future<ByteData?> send(String channel, ByteData? message) {
     final Completer<ByteData?> completer = Completer<ByteData?>();
-    ui.window.onPlatformMessage!(channel, message, (ByteData? reply) {
+    ui.channelBuffers.push(channel, message, (ByteData? reply) {
       try {
         completer.complete(reply);
       } catch (exception, stack) {
@@ -163,26 +163,6 @@
     else
       _handlers[channel] = handler;
   }
-
-  @override
-  bool checkMessageHandler(String channel, MessageHandler? handler) => _handlers[channel] == handler;
-
-  @override
-  void setMockMessageHandler(
-    String channel,
-    MessageHandler? handler,
-  ) {
-    throw FlutterError(
-      'Setting mock handlers is not supported on the platform side.',
-    );
-  }
-
-  @override
-  bool checkMockMessageHandler(String channel, MessageHandler? handler) {
-    throw FlutterError(
-      'Setting mock handlers is not supported on the platform side.',
-    );
-  }
 }
 
 /// This class was previously separate from [Registrar] but was merged into it
diff --git a/packages/flutter_web_plugins/test/plugin_registry_test.dart b/packages/flutter_web_plugins/test/plugin_registry_test.dart
index 008d721..73cb681 100644
--- a/packages/flutter_web_plugins/test/plugin_registry_test.dart
+++ b/packages/flutter_web_plugins/test/plugin_registry_test.dart
@@ -71,12 +71,5 @@
       ServicesBinding.instance!.defaultBinaryMessenger
           .setMessageHandler('test_send', null);
     });
-
-    test('throws when trying to set a mock handler', () {
-      expect(
-          () => pluginBinaryMessenger.setMockMessageHandler(
-              'test', (ByteData? data) async => ByteData(0)),
-          throwsFlutterError);
-    });
   });
 }