Bloc: How to initialize a Bloc with state during BlocTest

Created on 10 Mar 2020  路  4Comments  路  Source: felangel/bloc

I have a MyBloc bloc that accepts an event MyEventActivate. This event fails when MyBloc.state is not MyStateSuccess.

// * my_bloc.dart

/// mapEventToState for [MyEventActivate].
Stream<MyState> _activate() async* {
  if (state is MyStateSuccess) {
    yield MyStateParsedSuccess(state.data);
  } else {
    yield MyStateError('Cannot activate: wrong state $state');
  }
}

I want to test the functionality of MyEventActivate with something like this:

// * my_bloc_test.dart

blocTest(
      'Emits [MyStateParsedSuccess] when MyEventActivate is called & current state is MyStateSuccess',
      build: () async {
        final MyStateSuccess startState = MyStateSuccess(data: 'mock success');
        // TODO: somehow initialize bloc.state to `startState` here
        return bloc;
      },
      act: (MyBloc bloc) async => bloc.add(MyEventActivate()),
      expect: [MyStateParsedSuccess('mock success')],
    );

Is it possible to initialize MyBloc with a specific state startState during BlocTest.build? I have tried using BlocTest.skip which works OK, but then I still need to somehow run some business logic to end up at startState.

bloc_test question

Most helpful comment

That makes sense, your example is definitely the best example then. Thank you for making blocs easy to test!

All 4 comments

Hi @sterrenburg 馃憢
Thanks for opening an issue!

You can run whatever setup code you need in the build of blocTest and use skip to only assert for the state(s) after the setup.

blocTest(
  'emits 2 when CounterEvent.increment is added',
  build: () async => CounterBloc()..add(CounterEvent.increment),
  act: (bloc) => bloc.add(CounterEvent.increment),
  skip: 2,
  expect: [2],
);

Hope that helps 馃憤

Thank you for your answer!

That works as expected, and is how I am testing the event right now. The issue to me is that this approach requires some implementation for handling CounterEvent.increment, which is outside the responsibility of _activate.

In this example, I would like to start off with a MyBloc with some particular state that is not MyInitialState. That way, the test does not depend on the functionality that produces the particular state. Does that make sense, or am I approaching the modularity of the test in a wrong manner?

@sterrenburg I think the key thing to note is you're testing the real bloc so you only have access to the API of the real bloc. There is no magic way to initialize a bloc with a given state in a test and I would encourage you to think of each test as exercising a sequence of one or more events. You always need to start at the initialState but certain tests can add more events and build on functionality from previous tests. Hope that helps 馃憤

That makes sense, your example is definitely the best example then. Thank you for making blocs easy to test!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

RobPFarley picture RobPFarley  路  3Comments

hivesey picture hivesey  路  3Comments

nhwilly picture nhwilly  路  3Comments

wheel1992 picture wheel1992  路  3Comments

shawnchan2014 picture shawnchan2014  路  3Comments