测试超时应该取消 EventChannel 并抛出 TimeoutException

Test that timeout should cancel EventChannel and throw TimeoutException

我是 Flutter 的开源 Geolocator 插件的维护者,并致力于重构该插件。根据普遍要求,我正在尝试向检索当前位置的插件方法添加超时选项。

getCurrentLocation 方法主要是监听位置更新流,捕获第一个元素,然后取消流。现在我想提供一个选项来提供一个时间限制,当达到该时间限制时应该取消流并抛出一个 TimeoutException。在我开始在我的代码库中实现它之前,我决定从一个小的概念验证开始,看看我是否理解一切。结果我没有 ;)

我有以下代码:

import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  final eventChannel = EventChannel('demo');
  final log = <MethodCall>[];

  setUp(() async {
    log.clear();

    MethodChannel(eventChannel.name)
        .setMockMethodCallHandler((methodCall) async {
      log.add(methodCall);

      switch (methodCall.method) {
        case 'listen':
          await Future.delayed(Duration(milliseconds: 10));

          await ServicesBinding.instance.defaultBinaryMessenger
              .handlePlatformMessage(eventChannel.name,
                  eventChannel.codec.encodeSuccessEnvelope('one'), (_) {});

          await ServicesBinding.instance.defaultBinaryMessenger
              .handlePlatformMessage(eventChannel.name,
                  eventChannel.codec.encodeSuccessEnvelope('two'), (_) {});


          await ServicesBinding.instance.defaultBinaryMessenger
              .handlePlatformMessage(eventChannel.name,
                  eventChannel.codec.encodeSuccessEnvelope('three'), (_) {});
          break;
        case 'cancel':
        default:
          return null;
      }
    });
  });

  test('EventChannel returns the first value and cancels the stream', () async {
    final one = await eventChannel.receiveBroadcastStream().first;

    expect(one, 'one');
    expect(log, <Matcher>[
      isMethodCall('listen', arguments: null),
      isMethodCall('cancel', arguments: null),
    ]);
  });

  test('Timeout should cancel the stream', () async {
    final future = eventChannel
        .receiveBroadcastStream()
        .timeout(Duration(milliseconds: 5), onTimeout: (s) {
      s.close();
      throw TimeoutException('Timeout expired');
    }).first;

    expect(
      future,
      throwsA(predicate((e) {
        final isTimeout = e is Timeout;
        final streamCancelled = log.contains('cancel');
        return isTimeout && streamCancelled;
      })),
    );
  });
}

第一个测试(称为“”)按预期工作,它检索第一个值 "one" 然后取消流。

在第二个测试(称为“”)中,我试图测试流是否被取消,并且在达到超时时抛出 TimeoutException。这就是我挣扎的地方,看来我不明白如何实现这一目标。可能我没有正确理解内部工作原理。第二个测试中的 future 变量似乎是 return 流中的最后一个值,根本没有超时。请参阅以下输出:

00:00 +1: Timeout should cancel the stream [E]
  Expected: throws satisfies function
    Actual: <Instance of '_Future<dynamic>'>
     Which: emitted 'two'

  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 6327:7         DartError
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 4773:11        throw_
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 353347:17   fail
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 353325:18   _expect.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359718:140  <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359765:16   [_run]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359718:108  <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35912:56       _rootRunUnary
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35234:14       runUnary
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 30956:29       handleValue
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 31466:49       handleValueCallback
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 31498:17       _propagateToListeners
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 31348:25       [_complete]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35874:24       _cancelAndValue
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 18161:17       get first.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359718:140  <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359765:16   [_run]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359718:108  <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35912:56       _rootRunUnary
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35234:14       runUnary
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35153:14       runUnaryGuarded
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 29621:22       [_sendData]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 29569:26       [_add]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 30263:29       [_sendData]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 30067:24       add
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 18357:22       onData
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359718:140  <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359765:16   [_run]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359718:108  <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35912:56       _rootRunUnary
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35234:14       runUnary
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35153:14       runUnaryGuarded
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 29621:22       [_sendData]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 32758:28       perform
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 32861:15       handleNext
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 32621:16       schedule.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359765:16   [_run]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359713:86   <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35903:56       _rootRun
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35227:14       run
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35144:14       runGuarded
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35183:33       bindCallbackGuarded.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359765:16   [_run]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359713:86   <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35906:14       _rootRun
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35227:14       run
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35144:14       runGuarded
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35183:33       bindCallbackGuarded.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35756:13       _microtaskLoop
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35762:13       _startMicrotaskLoop
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 31704:9        _scheduleImmediateWithPromise.<fn>
  ===== asynchronous gap ===========================
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35255:14       registerUnaryCallback
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 31164:27       then
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 353323:23   _expect
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 353277:12   expect[=11=]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 343286:12   expect$
  frame_dark.html#/%20line%2038%20%3E%20scriptElement 119:21                                     main[=11=].<fn>.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35674:34       runBody
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35702:7        _async
  frame_dark.html#/%20line%2038%20%3E%20scriptElement 114:78                                     main[=11=].<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 347466:17   test.<fn>.<fn>.<fn>.<fn>.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35655:33       onValue
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359718:140  <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359765:16   [_run]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359718:108  <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35912:56       _rootRunUnary
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35234:14       runUnary
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 30956:29       handleValue
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 31466:49       handleValueCallback
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 31498:17       _propagateToListeners
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 31348:25       [_complete]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 30714:32       doWhile.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359718:140  <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359765:16   [_run]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359718:108  <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35912:56       _rootRunUnary
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35234:14       runUnary
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35153:14       runUnaryGuarded
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35187:34       bindUnaryCallbackGuarded.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359718:140  <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359765:16   [_run]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359718:108  <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35912:56       _rootRunUnary
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35234:14       runUnary
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 30956:29       handleValue
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 31466:49       handleValueCallback
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 31498:17       _propagateToListeners
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 31357:23       [_completeWithValue]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 31377:35       <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359765:16   [_run]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359713:86   <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35906:14       _rootRun
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35227:14       run
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35144:14       runGuarded
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35183:33       bindCallbackGuarded.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35756:13       _microtaskLoop
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35762:13       _startMicrotaskLoop
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 31704:9        _scheduleImmediateWithPromise.<fn>
  ===== asynchronous gap ===========================
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35255:14       registerUnaryCallback
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35666:22       _async
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 347464:134  test.<fn>.<fn>.<fn>.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 348487:15   waitForOutstandingCallbacks.<fn>.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35674:34       runBody
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35702:7        _async
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 348484:60   waitForOutstandingCallbacks.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35906:14       _rootRun
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35227:14       run
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 36041:92       _runZoned
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 36006:18       runZoned
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 348484:13   waitForOutstandingCallbacks
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 347464:86   test.<fn>.<fn>.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35906:14       _rootRun
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35227:14       run
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 36041:92       _runZoned
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 36006:18       runZoned
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 347464:21   test.<fn>.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35674:34       runBody
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35702:7        _async
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 347454:109  test.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 348572:40   <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35674:34       runBody
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35702:7        _async
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 348571:70   <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 30523:31       new.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359765:16   [_run]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359713:86   <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35903:56       _rootRun
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35227:14       run
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35144:14       runGuarded
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35183:33       bindCallbackGuarded.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359765:16   [_run]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 359713:86   <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35906:14       _rootRun
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35227:14       run
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35171:33       bindCallback.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 22859:11       internalCallback
  ===== asynchronous gap ===========================
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35248:14       registerCallback
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35182:29       bindCallbackGuarded
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 34399:74       new
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 34409:19       run
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 30521:21       new
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 348571:46   <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35674:34       runBody
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35702:7        _async
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 348568:64   <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35906:14       _rootRun
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35227:14       run
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 36041:92       _runZoned
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 36006:18       runZoned
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 348568:17   <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 348593:9    [_guardIfGuarded]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 348567:30   <fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 354673:18   capture.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35906:14       _rootRun
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35227:14       run
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 36041:92       _runZoned
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 36006:18       runZoned
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 354671:20   capture
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 348566:20   [_onRun]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 4978:16        _checkAndCall
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 5021:17        callMethod
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 5024:17        dsend
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 356872:12   [_run]
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/flutter_web.js 356792:41   run
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 30536:31       microtask.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35903:56       _rootRun
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35227:14       run
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35144:14       runGuarded
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35183:33       bindCallbackGuarded.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35906:14       _rootRun
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35227:14       run
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35144:14       runGuarded
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35183:33       bindCallbackGuarded.<fn>
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35756:13       _microtaskLoop
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 35762:13       _startMicrotaskLoop
  https://storage.googleapis.com/compilation_artifacts/2.9.0-8.2.beta/dart_sdk.js 31704:9        _scheduleImmediateWithPromise.<fn>

我做错了什么?是否可以编写这样的测试?非常感谢任何帮助。

更新: 我已将 link 删除到 DartPad,因为它不会 运行 测试环境中的代码(如 flutter test ), 可能导致漏报。

在 Flutter 社区(尤其是 Simon Lightfoot)的大力帮助下,我解决了这个问题。

我的代码有两个错误。

  1. 由于我正在处理一个流,我不应该抛出一个 TimeoutException 而是向接收器添加一个错误;
  2. 为了模拟一个很长的 运行 任务,我用 10 毫秒的延迟阻塞了事件通道。这意味着在抛出超时后,我仍然应该在处理 cancel 方法调用之前等待剩余的 5 毫秒。

所以经过一些重构后,我得到了以下可行的解决方案:

  test('Timeout should cancel the stream', () async {
    final future = eventChannel
      .receiveBroadcastStream()
      .timeout(Duration(milliseconds: 5), onTimeout: (s) {
        s.addError(TimeoutException('Timeout expired'));
        s.close();
      }).first;

    expect(
      future,
      throwsA(isA<TimeoutException>()),
    );

    await Future.delayed(Duration(milliseconds: 5));

    expect(log, <Matcher>[
      isMethodCall('listen', arguments: null),
      isMethodCall('cancel', arguments: null),
    ]);
  });