简体   繁体   English

Flutter:如何使用 blocTest 对 Bloc 使用的计时器进行单元测试?

[英]Flutter: How can I unit test a Timer used by a Bloc using blocTest?

How can I test a Timer inside a Bloc, using blocTest ?如何使用blocTest在 Bloc 中测试 Timer? I'm using the bloc library , with freezed to build the state and event objects (might not matter here, but who knows).我正在使用bloc libraryfreezed来构建 state 和事件对象(在这里可能无关紧要,但谁知道呢)。

So let's say I have something like this in my bloc class:假设我的 bloc class 中有这样的东西:

@override
Stream<MyState> mapEventToState(
    MyEvent event,
    ) {
  return event.when(
    start: (value) async* {
      yield state.copyWith(/* add state data */);
    },
    getStream: _myStream(),
  );
}

Stream<MyState> _myStream() async* {
  MyResult? result;

  try {
    final repo = await _repoProvider();
    result = await repo.fetchResult();
  } on Exception catch (e) {
    _logger.e(e);
    /* do some stuff irrelevant to the example */
  }
  
  Timer(const Duration(minutes: 1), () {
      add(const MyEvent.getStream());

  });

  yield state.copyWith(
  /* fill state object with data*/
  );
}

So if my bloc receives a getStream event, the _myStream() function is called to handle the emitting.因此,如果我的集团收到 getStream 事件,将调用 _myStream() function 来处理发射。 This function starts a timer, to submit another getStream event after 1 minute.这个 function 启动一个计时器,在 1 分钟后提交另一个 getStream 事件。 How can I test this in a unit test without having to wait for a minute (I'm using bloc library's bloc_test to write blocTest functions for my blocs. This comes with a wait functionality, but it really just waits for the submitted amount of time)?我如何在单元测试中测试它而不必等待一分钟(我正在使用 bloc 库的 bloc_test 为我的 blocs 编写 blocTest 函数。它带有等待功能,但它实际上只是等待提交的时间量)? I've tried to solve this using FakeAsync, but to no avail - I could always only register the first event.我尝试使用 FakeAsync 解决这个问题,但无济于事——我总是只能注册第一个事件。 I thought something like this would work, but it doesn't: blocTest<MyBloc, MyState>( "repo should be called twice", build: () {我认为这样的事情会起作用,但它不起作用: blocTest<MyBloc, MyState>( "repo should be called twice", build: () {

    return TravelBloc(
     
      mockRepoProvider,
      mockTrackerProvider,
    );
  },
  act: (bloc) =>
      fakeAsync((async) {
        bloc.add(const MyEvent.getStream());
        async.elapse(Duration(minutes: 1, seconds: 1));
      }),
  expect: () => [
       /* check state here */
      ],
  verify: (_) {
    verify(mockRepo.fetchResult).called(2);
  });

Is there any good solution how to test such a construction properly without actual waiting?有没有什么好的解决方案如何在没有实际等待的情况下正确测试这样的结构? fakeAsync seems to be the correct choice but I see myself unable to combine it with blocTest . fakeAsync似乎是正确的选择,但我认为自己无法将其与blocTest结合使用。

As you mentioned wait parameter from the blocTest method should be used for testing the things like timers, debounces, etc. However, in your case, this wouldn't be sufficient, because your unit test(s) become too slow to execute.正如您提到的blocTest方法中的wait参数应用于测试计时器、去抖动等。但是,在您的情况下,这还不够,因为您的单元测试执行起来太慢了。

You have just to apply the DI principle (by the way, you are already using it when you supply mocks to the BLoC) and provide the Duration object to your TravelBloc 's constructor.您只需应用DI 原则(顺便说一句,当您向 BLoC 提供模拟时,您已经在使用它)并向TravelBloc的构造函数提供Duration object。 So your build callback from blocTest will look like this:因此,来自blocTestbuild回调将如下所示:

blocTest(
...
build: () => TravelBloc(
       mockRepoProvider,
       mockTrackerProvider,
       updateInterval: tUpdateInterval,
),
...
);

This technique is very helpful when you need to "control" something inside your class/method within your test.当您需要在测试中“控制”类/方法中的某些内容时,此技术非常有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM