Testing StreamController with one listener present

105 Views Asked by At

I wanted to know how are StreamController with listener assigned or implemented are tested.

I have a class as follows:

class Foo<T>{
  
  late final StreamController<T> _streamController;
  
  Foo(){
    _streamController = StreamController<T>();
    _streamController.stream.listen((T data)=> _aListner); // listner attached to the stream.

  }
  
  void _aListner(T data){
    // doing something with the data
    print(data);
  }
  
  void addData(T data){
    _streamController.add(data);
  }
  
  Stream<T> get stream => _streamController.stream;
  
}

I want to implement an test to check if data is added to the stream in order (a simple test using the Stream matcher). But it always throws an error that the stream has already been listened to.

test implementation:

test('stream getter  test.', ()async {
  
      final Foo<String> foo = Foo<String>();  
      const String data1 = 'data1';
      const String data2 = 'data2';
      const String data3 = 'data3';
      const String data4 = 'data4';


      foo.addData(data1);
      foo.addData(data2);
      foo.addData(data3);
      foo.addData(data4);


      print(foo.stream.length); // even this throws- Bad state: Stream has already been listened to.
    });

I know converting the _streamController to broadcast would resolve the issue. But the defined class has only one listener function and this is by design, so no need of making it broadcast stream.

I can Mock the class using mockito, but the constructor mocking is not supported ( I may be wrong here please correct me, if so).

The main objective here is used to StreamMatcher in test cases and use emitsInOrder or emits, read here.

1

There are 1 best solutions below

4
On

Stream.length is adding a new listener, because it will listen to the stream and try to count the number of events. You are listening twice now.

You can add a property foo.length and change the method _aListner to

void _aListner(T data){
  // doing something with the data
  print(data);
  length++;
}

Now you can test foo.length instead of foo.stream.length.