如何正确测试颤振块

Posted

技术标签:

【中文标题】如何正确测试颤振块【英文标题】:How to test flutter bloc correctly 【发布时间】:2021-06-12 22:48:38 【问题描述】:

今天我尝试添加我的第一个测试,但我马上遇到了问题。我遵循了许多教程并阅读了更多内容,但我无法使用 flutter_test 或 bloc_test 库进行简单的 LoginBloc 测试。我不得不做一些根本错误的事情,但我就是找不到。我认为它与堆栈跟踪中的以下行有关:The argument type 'Bloc<Event, State>' can't be assigned to the parameter type 'dynamic Function()'.

这是整个堆栈跟踪:

/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/bloc_test-8.0.0-nullsafety.0/lib/src/when_listen.dart:52:10: Error: The argument type 'Bloc<Event, State>' can't be assigned to the parameter type 'dynamic Function()'.
 - 'Bloc' is from 'package:bloc/src/bloc.dart' ('/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/bloc-7.0.0-nullsafety.3/lib/src/bloc.dart').
    when(bloc).calls(#state).thenReturn(initialState);
         ^
/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/bloc_test-8.0.0-nullsafety.0/lib/src/when_listen.dart:52:16: Error: The method 'calls' isn't defined for the class 'When<dynamic>'.
 - 'When' is from 'package:mocktail/src/mocktail.dart' ('/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/mocktail-0.0.2-dev.5/lib/src/mocktail.dart').
Try correcting the name to the name of an existing method, or defining a method named 'calls'.
    when(bloc).calls(#state).thenReturn(initialState);
               ^^^^^
/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/bloc_test-8.0.0-nullsafety.0/lib/src/when_listen.dart:55:8: Error: The argument type 'Bloc<Event, State>' can't be assigned to the parameter type 'dynamic Function()'.
 - 'Bloc' is from 'package:bloc/src/bloc.dart' ('/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/bloc-7.0.0-nullsafety.3/lib/src/bloc.dart').
  when(bloc).calls(#listen).thenAnswer((invocation) 
       ^
/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/bloc_test-8.0.0-nullsafety.0/lib/src/when_listen.dart:55:14: Error: The method 'calls' isn't defined for the class 'When<dynamic>'.
 - 'When' is from 'package:mocktail/src/mocktail.dart' ('/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/mocktail-0.0.2-dev.5/lib/src/mocktail.dart').
Try correcting the name to the name of an existing method, or defining a method named 'calls'.
  when(bloc).calls(#listen).thenAnswer((invocation) 
             ^^^^^
/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/bloc_test-8.0.0-nullsafety.0/lib/src/when_listen.dart:58:14: Error: The argument type 'Bloc<Event, State>' can't be assigned to the parameter type 'dynamic Function()'.
 - 'Bloc' is from 'package:bloc/src/bloc.dart' ('/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/bloc-7.0.0-nullsafety.3/lib/src/bloc.dart').
        when(bloc).calls(#state).thenReturn(state);
             ^
/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/bloc_test-8.0.0-nullsafety.0/lib/src/when_listen.dart:58:20: Error: The method 'calls' isn't defined for the class 'When<dynamic>'.
 - 'When' is from 'package:mocktail/src/mocktail.dart' ('/C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/mocktail-0.0.2-dev.5/lib/src/mocktail.dart').
Try correcting the name to the name of an existing method, or defining a method named 'calls'.
        when(bloc).calls(#state).thenReturn(state);
                   ^^^^^
dart:async/stream_controller.dart 561:44                       _StreamController.addError
dart:async/stream_controller.dart 830:13                       _StreamSinkWrapper.addError
package:stream_channel/src/guarantee_channel.dart 145:14       _GuaranteeSink._addError
package:stream_channel/src/guarantee_channel.dart 136:5        _GuaranteeSink.addError
package:flutter_tools/src/test/flutter_platform.dart 439:27    FlutterPlatform._startTest
===== asynchronous gap ===========================
dart:async/zone.dart 1286:19                                   _CustomZone.registerUnaryCallback
dart:async-patch/async_patch.dart 40:23                        _asyncThenWrapperHelper
package:flutter_tools/src/test/flutter_platform.dart 341:36    FlutterPlatform.loadChannel
package:flutter_tools/src/test/flutter_platform.dart 306:44    FlutterPlatform.load
package:test_core/src/runner/loader.dart 225:38                Loader.loadFile.<fn>
===== asynchronous gap ===========================
dart:async/zone.dart 1286:19                                   _CustomZone.registerUnaryCallback
dart:async-patch/async_patch.dart 40:23                        _asyncThenWrapperHelper
package:test_core/src/runner/loader.dart                       Loader.loadFile.<fn>
package:test_core/src/runner/load_suite.dart 97:31             new LoadSuite.<fn>.<fn>
package:test_core/src/runner/load_suite.dart 96:17             new LoadSuite.<fn>.<fn>
package:test_core/src/runner/load_suite.dart 107:8             new LoadSuite.<fn>
package:test_api/src/backend/invoker.dart 231:15               Invoker.waitForOutstandingCallbacks.<fn>
package:test_api/src/backend/invoker.dart 228:14               Invoker.waitForOutstandingCallbacks.<fn>
dart:async/zone.dart 1354:13                                   _rootRun
dart:async/zone.dart 1258:19                                   _CustomZone.run
dart:async/zone.dart 1788:10                                   _runZoned
dart:async/zone.dart 1710:10                                   runZoned
package:test_api/src/backend/invoker.dart 228:5                Invoker.waitForOutstandingCallbacks
package:test_api/src/backend/invoker.dart 383:17               Invoker._onRun.<fn>.<fn>.<fn>
===== asynchronous gap ===========================
dart:async/zone.dart 1286:19                                   _CustomZone.registerUnaryCallback
dart:async-patch/async_patch.dart 40:23                        _asyncThenWrapperHelper
package:test_api/src/backend/invoker.dart                      Invoker._onRun.<fn>.<fn>.<fn>
dart:async/zone.dart 1354:13                                   _rootRun
dart:async/zone.dart 1258:19                                   _CustomZone.run
dart:async/zone.dart 1788:10                                   _runZoned
dart:async/zone.dart 1710:10                                   runZoned
package:test_api/src/backend/invoker.dart 370:9                Invoker._onRun.<fn>.<fn>
dart:async/zone.dart 1354:13                                   _rootRun
dart:async/zone.dart 1258:19                                   _CustomZone.run
dart:async/zone.dart 1788:10                                   _runZoned
dart:async/zone.dart 1710:10                                   runZoned
package:test_api/src/backend/invoker.dart 150:7                Invoker.guard
package:test_api/src/backend/invoker.dart 413:15               Invoker._guardIfGuarded
package:test_api/src/backend/invoker.dart 369:7                Invoker._onRun.<fn>
package:stack_trace/src/chain.dart 94:24                       Chain.capture.<fn>
dart:async/zone.dart 1354:13                                   _rootRun
dart:async/zone.dart 1258:19                                   _CustomZone.run
dart:async/zone.dart 1788:10                                   _runZoned
dart:async/zone.dart 1710:10                                   runZoned
package:stack_trace/src/chain.dart 92:12                       Chain.capture
package:test_api/src/backend/invoker.dart 368:11               Invoker._onRun
package:test_api/src/backend/live_test_controller.dart 153:11  LiveTestController.run
dart:async/future.dart 198:37                                  new Future.microtask.<fn>
dart:async/zone.dart 1346:47                                   _rootRun
dart:async/zone.dart 1258:19                                   _CustomZone.run
dart:async/zone.dart 1162:7                                    _CustomZone.runGuarded
dart:async/zone.dart 1202:23                                   _CustomZone.bindCallbackGuarded.<fn>
dart:async/zone.dart 1354:13                                   _rootRun
dart:async/zone.dart 1258:19                                   _CustomZone.run
dart:async/zone.dart 1162:7                                    _CustomZone.runGuarded
dart:async/zone.dart 1202:23                                   _CustomZone.bindCallbackGuarded.<fn>
dart:async/schedule_microtask.dart 40:21                       _microtaskLoop
dart:async/schedule_microtask.dart 49:5                        _startMicrotaskLoop
dart:isolate-patch/isolate_patch.dart 120:13                   _runPendingImmediateCallback
dart:isolate-patch/isolate_patch.dart 185:5                    _RawReceivePortImpl._handleMessage

Failed to load "######\test\bloc\login\login_bloc_test.dart":
Compilation failed
Test: ######\test\bloc\login\login_bloc_test.dart
Shell: C:\src\flutter\bin\cache\artifacts\engine\windows-x64\flutter_tester.exe

这是我的 login_bloc_test:

class MockAppRepository extends Mock implements Repository 

void main() 
  MockAppRepository repository = MockAppRepository();
  setUp(() 
    repository = MockAppRepository();
  );

  group('LoginBloc test', () 
    final user =
        User(1, 'email', 'firstName', 'lastName', 'status', 'username', null);
    
    test('emits LoginLoading & LoginSuccess after successful login', () 
      when(repository.logIn('email', 'password'))
          .thenAnswer((realInvocation) async => user);

      final bloc = LoginBloc(repository);
      bloc.add(LogIn('email', 'password'));

      expectLater(
          bloc,
          emitsInOrder([
            LoginInitial(),
            LoginLoading(),
            LoginSuccess(user),
          ]));
    );

    blocTest<LoginBloc, LoginState>(
      'emits LoginLoading & LoginSuccess after successful login',
      build: () 
        when(repository.logIn('email', 'password'))
            .thenAnswer((realInvocation) async => user);
        return LoginBloc(repository);
      ,
      act: (bloc) => bloc.add(LogIn('email', 'password')),
      expect: () => [
        LoginInitial(),
        LoginLoading(),
        LoginSuccess(user),
      ],
    );
  );



【问题讨论】:

【参考方案1】:

好吧,如果有人期待同样的问题,那么有更新的 bloc_test 版本正在解决这个问题。 bloc_test: 8.0.0-nullsafety.5 是你想要的。

【讨论】:

【参考方案2】:

第二个测试是:

expect: <LoginState>[
        LoginInitial(),
        LoginLoading(),
        LoginSuccess(user),
      ],

【讨论】:

以上是关于如何正确测试颤振块的主要内容,如果未能解决你的问题,请参考以下文章

颤振测试块错误类型'Null'不是类型的子类型

颤振测试中的非空变量

选择不依赖于状态的正确颤振块小部件

颤振小部件测试 - 如何执行“返回上一个屏幕”的测试

如何在颤振测试中初始化 ScreenUtil.init()?

如何在我的颤振测试中生成未测试文件的测试覆盖率?