Mol0ko
Mol0ko

Reputation: 3298

Dart tests: excpect stream to emit nothing

I want to check that some Stream (e.g. bloc) emits nothing during unit test.

More detailed description: I use mockito and flutter_bloc packages. System under test is a bloc. My test:

  test('sut emits nothing', () {
    final event = SomeEvent(false);
    sut.add(event);
    expectLater(
      sut,
      emitsNothing,    // <---- HERE I want to check that sut emits nothing
    );
  });

Here is mapping function of my bloc:

  @override
  Stream<State> mapEventToState(Event event) async* {
    if (event is SomeEvent) {
      // If `flag` is true - then bloc emits a state,
      // if `flag` is false - then bloc emits nothing.
      if (event.flag) {    
        yield State.someState;
      }
    }
  }

Here is code of SomeEvent:

abstract class Event extends Equatable {}

class SomeEvent extends Event {
  final bool flag;

  SomeEvent(this.flag);

  @override
  List<Object> get props => [flag];
}

Can I check it out? Any help appreciated.

Upvotes: 3

Views: 2026

Answers (3)

Rushikesh Kumbhar
Rushikesh Kumbhar

Reputation: 96

I hope this issue is still relevant.

Actually, there's no need to write streams & yield statements from scratch, as per the newer versions of bloc. But as we are setting the Later calles in testing, we will need to parse a bloc-stream while expecting the result. So, the solution to your code is to use bloc.stream instead of bloc.state which converts the bloc to a bloc stream & yeilds the output in order. Do remember that the stream does not contain the initial/EmptyState(), but all other events are handle in order & hence emitted the same. Refer to the below code snippet for the proper implementat,

This is the bloc file that contains the bloc logic as per the latest versions.

///<inputs an event, outputs the state> => <NumberTriviaEvent, 
NumberTriviaState>
class NumberTriviaBloc extends Bloc<NumberTriviaEvent, NumberTriviaState> {
  final GetConcreteNumberTrivia concreteNumberTrivia;
  final GetRandomNumberTrivia randomNumberTrivia;
  final InputConverter inputConverter;

  NumberTriviaBloc(
      {required this.concreteNumberTrivia,
      required this.randomNumberTrivia,
      required this.inputConverter}) : super(EmptyState()) {
    on<NumberTriviaEvent>((event, emit) async{
        if(event is GetTriviaForConcreteNumber){
          final input = inputConverter.stringToUnsignedInteger(event.numberString);
          input.fold((lFailure){
             emit( const ErrorState(errorMessage: INVALID_INPUT_FAILURE_MESSAGE));
          }, (rSuccess) {
             emit(const LoadedState(numberTrivia: NumberTrivia(text: 'sample test', number: 1)));
          });
        }
    });
  }
}

This is the test file that tests the output over the block that is written above.

    test('should emit [Error] when theres an invalid input', () {
      //  arrange
      when(inputConverter.stringToUnsignedInteger('abc'))
          .thenAnswer((realInvocation) => Left(InvalidInputFailure()));

      //  assert Later
      /// As we will be checking if the emit contains the expected result, we will use expectLater() method in test
      /// which puts the particular test on hold until the data is been emitted(upper limit 30 seconds) & then applies the checks
      expectLater(
        bloc.stream,
        emitsInOrder([
          const ErrorState(errorMessage: INVALID_INPUT_FAILURE_MESSAGE)
          ]));

      //  act
      bloc.add(const GetTriviaForConcreteNumber(numberString: 'abc'));
    });
  });

Learning Source: Reso Coders

Upvotes: 0

Ber
Ber

Reputation: 41833

If you are using the flutter_test library, you can use neverEmits(anything):

test('sut emits nothing', () async {
  final event = SomeEvent(false);
  sut.add(event);

  unawaitet(expectLater(sut, neverEmits(anything)));
  await sut.close();
);

});

It is imported to close the stream at the end of the test, otherwise the test will time out in the good case.

It does not seem to be sufficient if the stream is closed in tearDown().

Upvotes: 4

Umair M
Umair M

Reputation: 10720

you can achieve this by using bloc_test package.

blocTest(
  'CounterBloc emits no events',
  build: () => CounterBloc(),
  act: (_) {}, // no action taken
  expect: [], // no event emitted
);

Upvotes: 3

Related Questions