你如何测试一个消耗流的颤振块

Posted

技术标签:

【中文标题】你如何测试一个消耗流的颤振块【英文标题】:how do you test a flutter block that consumes a stream 【发布时间】:2021-09-21 12:03:51 【问题描述】:

我有一个块来侦听身份验证事件的流(侦听 firebase 用户事件)。我的障碍是;

class AuthenticationBloc
    extends Bloc<AuthenticationEvent, AuthenticationLoadingState> 
  StreamSubscription<AuthenticationDetail> streamSubscription;
  CheckAuthenticationStatus authenticationStatus;

  AuthenticationBloc(@required CheckAuthenticationStatus authenticationStatus)
      : assert(authenticationStatus != null),
        assert(authenticationStatus.getStream() != null),
        this.authenticationStatus = authenticationStatus,
        super(AuthenticationLoadingState().init()) 
    this.streamSubscription = this
        .authenticationStatus
        .getStream()
        .listen((AuthenticationDetail detail) async* 
          print(detail.toString());
      add(StatusChanged(detail));
    );
  

  @override
  Stream<AuthenticationLoadingState> mapEventToState(
      AuthenticationEvent event) async* 
    if (event is ListenToAuthenticationEvents) 
      print('well well well');
     else if (event is StatusChanged) 
      print('yeeee');
    
  

  @override
  Future<void> close() 
    this.streamSubscription?.cancel();
    return super.close();
  

  Future<AuthenticationLoadingState> init() async 
    return state.clone();
  

提供的用例是;

class CheckAuthenticationStatus
    implements UseCaseListner<AuthenticationDetail> 
  final AuthenticationRepository authenticationRepository;

  CheckAuthenticationStatus(@required this.authenticationRepository);

  @override
  Stream<AuthenticationDetail> getStream() =>
      authenticationRepository.getAuthDetailStream();

我正在尝试编写一个 bloc 测试,我可以在其中模拟用例并添加我自己的流,我可以将事件发送到如下;

class MockCheckAuthenticationStatus extends Mock
    implements CheckAuthenticationStatus 

void main() 

  MockCheckAuthenticationStatus authenticationStatus;
  AuthenticationBloc authenticationBloc;
  StreamController controller;
  Stream<AuthenticationDetail> stream;

  setUp(() 
    controller = StreamController<AuthenticationDetail>();
    stream = controller.stream;
    authenticationStatus = MockCheckAuthenticationStatus();

  );


  test('initial state is correct', () async 
    var authenticationDetail = AuthenticationDetail(isValid: true);
    when(authenticationStatus.getStream()).thenAnswer((_) => stream);
    authenticationBloc =
        AuthenticationBloc(authenticationStatus: authenticationStatus);
//this should action, but doesnt, why?
    controller.add(authenticationDetail);
    await untilCalled(authenticationStatus.getStream());
    verify(authenticationStatus.getStream());

  );
tearDown(() 
    authenticationBloc?.close();
    controller?.close();
  );

期望controller.add(authenticationDetail) 将生成事件,我希望去 mapEventToState 讨论集团内的这些事件。然而这并没有发生。

简而言之,我如何通过发送流事件而不是以编程方式使用 bloc.add() 事件来测试 bloc。

【问题讨论】:

查看How to Ask 来改进这个问题 【参考方案1】:

问题的前提是基于官方 Firebase 身份验证文档,其中指出

Events are fired when the following occurs:

 - Right after the listener has been registered. 
 - When a user is signed in. 
 - When the current user is signed out.

所以不是注册一个监听器,而是通过一个事件调用 getUser。只需注册监听器也应该触发第一个事件,然后我们可以使用该事件进行相应的导航。我的测试目的是模拟第一个事件。

代码中的错误是 AuthenticationBloc 构造函数中 .listen((AuthenticationDetail detail) async* 行上的 async*

【讨论】:

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

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

如何将 dispose 与颤振块一起使用?

如何在颤振测试覆盖率中排除文件?

基于流的颤振小吃店展示

如何在 initState 方法中访问颤振块?

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