How to mock BLoC in Integration Test

1,460

You should try to mock SummaryRepository instead of the Bloc. That will allow you to test the behavior of the bloc and keeping control of what the repository returns to the stream.

class MockSummaryRepository extends Mock implements SummaryRepository{}

var mockRepository = MockSummaryRepository();
when(mockRepository.getSummary()).thenReturn(mockSummary);

final SummaryBloc summaryBloc = SummaryBloc(mockRepository);
Share:
1,460
Thomas
Author by

Thomas

Updated on December 13, 2022

Comments

  • Thomas
    Thomas over 1 year

    I have a Flutter app that uses the bloc and flutter_bloc packages. I am trying to write an integration test using flutter_driver and mockito. How do I mock the BlocProvider and its children to always emit a single mocked state?

    The original bloc:

    class SummaryBloc extends Bloc<BlocEvent, BlocState> {
      final SummaryRepository repository;
    
      SummaryBloc(this.repository);
    
      @override
      BlocState<Summary> get initialState => BlocStateEmpty<Summary>();
    
      @override
      Stream<BlocState> mapEventToState(
        BlocEvent event,
      ) async* {
        if (event is Fetch) yield BlocStateSuccess<Summary>(repository.getSummary());
      }
    }
    

    I have tried mocking the bloc and overriding the state getter:

    class MockSummaryBloc extends Mock implements SummaryBloc {}
    

    Then using mockito in the instrumented app:

    final MockSummaryBloc summaryBloc = MockSummaryBloc();
    
    // whenever the state stream getter is called, return the mocked stream.
    when(summaryBloc.state).thenAnswer((_) async* {
        yield BlocStateSuccess<Summary>(mockSummary);
      });
    

    For good measure I have tried the same for initialState.

    To use the mock in the instrumented app, I use BlocProvider.value:

    runApp(BlocProvider.value(
        value: summaryBloc,
        child: MaterialApp(
          title: 'Test Driver',
          home: Scaffold(
              body: BlocBuilder(
            bloc: summaryBloc,
            // the builder rebuilds on state change.
            builder: (context, state) {
              return Text('state: ${state?.runtimeType ?? 'isNull'}');
            },
          )),
        ),
      ));
    

    I expect the Text widget to print BlocStateSuccess<Summary> during runtime. However, the state is null during the lifespan of the driver test.

    Am I incorrectly mocking this Bloc? Are there other methods of mocking a Bloc, or Stream<BlocState>?