How to unit test Stream.listen() in Dart
Asked Answered
D

2

16

Consider the following test code ...

main() {
  StreamController controller;
  setUp(() {
    controller = StreamController.broadcast(sync: false);
  });

  tearDown(() {
    controller.close();
  });

  test('Stream listen test', () {
    var stream = controller.stream;

    stream.listen((event) {
      // >>>>> How can I test if this was called?? <<<<<<
    });

    controller.add('Here is an event!');
  });
}

... what is the correct way to test that the stream.listen(...) call-back was invoked?

stream.listen(...) doesn't return a Future so traditional expectAsyncX style matchers will not work here.

Perhaps there is some way to use the StreamSubscription.asFuture() that is returned by stream.listen(...)?

Dneprodzerzhinsk answered 16/6, 2019 at 18:25 Comment(0)
H
31

You can use expectLater function to wait for async response from your Stream and compare your Stream to your emitted value using emits , like this:

  test('Stream listen test', () {
    var stream = controller.stream;

    final String value = 'Here is an event!';

    stream.listen((event) {
      // >>>>> How can I test if this was called?? <<<<<<
    });

    expectLater(stream, emits(value));

    controller.add(value);
  });

UPDATE

You can try expectAsync1 around your listen method. If no value is emitted, the timeout will be fired.

stream.listen(
      expectAsync1(
        (event) {
          expect(event, value);
        },
      ),
    );
Howler answered 16/6, 2019 at 18:37 Comment(4)
This will only confirm that the value was emitted ... not that the function inside stream.listen() was invoked. I'm looking for a way to confirm that the listener was invoked.Dneprodzerzhinsk
It will confirm that the function was called. That is precisely what expectAsync1 does: It wraps a function, and requires that the wrapper function is called, otherwise the test won't be successful. When the wrapper function is called, it will definitely call the function it wraps. So, if the test is successful, then you can be certain that the function argument to expectAsync1 was also called (exactly once).Jeweller
Expanded example of expectAsync1Pistil
You saved my day! Thanks for the tip, not that easy to find in my opinion! Cheers!Emmeram
I
1

In case it helps anyone else, here's how I would test this using mocktail:

  test('Stream listen test', () {
    var stream = controller.stream;

    stream.listen((event) {
      myMockClass.myMethod(event);
    });

    controller.add('Here is an event!');
    
    await pumpEventQueue();
    
    verify(() => myMockClass.myMethod("Here is an event!")).called(1);
  });

Note the await pumpEventQueue() which is needed to ensure that the stream events are processed.

Reference: https://manichord.com/blog/posts/test-streams-in-flutter.html

Incur answered 8/5 at 14:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.