Flutter Widget Testing for BlocBuilder Widgets

Issue

I have a Widget which uses bloc builder to map the different state of widget.

class BodyWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return BlocBuilder<NewsBloc, NewsState>(builder: (context, state) {
          return state.map(
            .....
          );
        });
      }
    ....
    }

The BodyWidget is created in a Widget with BlocProvider.

class MainPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) =>
          getIt<NewsBloc>()..add(const NewsEvent.fetchNewsData()),
      child: BodyWidget(),
    );
  }
....
}

And the NewsBloc is defined as

@injectable
class NewsBloc extends Bloc<NewsEvent, NewsState> {
  final GetNews getNews;
  NewsBloc({
    @required this.getNews,
  }) : super(const _Initial());

  @override
  Stream<NewsState> mapEventToState(
    NewsEvent event,
  ) async* { ... }
}

I am using get_it and injectable for Dependency Injection.

Now I am trying to write a simple widget test for BodyWidget and I am not so sure how to inject all these dependency in test.

class MockBuildContext extends Mock implements BuildContext {}

class MockNewsBloc extends Mock implements NewsBloc {}

void main() {
  ForYouNewsTab _widget;
  MockBuildContext _context;
  NewsBloc _newsBloc;

  Widget makeTestableWidgets({Widget child}) {
    return MaterialApp(
      home: Scaffold(
        // body: BlocProvider(
        //   create: (_context) => getIt<NewsBloc>(),
        //   child: child,
        // ),
        body: child,
      ),
    );
  }

  setUp(() {
    _context = MockBuildContext();
    _widget = ForYouNewsTab();
  });

  test('ForYouNewsTab is sub class of StatelessWidget', () {
    expect(_widget, isA<StatelessWidget>());
  });

  testWidgets('should return sized box for initial state',
      (WidgetTester tester) async {
    await tester.pumpWidget(makeTestableWidgets(child: _widget));
  });
}

I did search in stackoverflow, but could not found a solution that works form me.

Solution

I solved my issue by following very basic steps. Not so sure if its the right way. Anyway if anyone ever comes to the same problem, it might help them.

class MainPage extends StatelessWidget {

  //added line
  final NewsBloc newsBloc;

  const MainPage({
    Key key, 
    @required this. newsBloc,
  })

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      // changed line
      // create: (context) => getIt<NewsBloc>()..add(const NewsEvent.fetchNewsData()),
      create: (context) => newsBloc..add(const NewsEvent.fetchNewsData()),
      child: BodyWidget(),
    );
  }

  ....

 }

Now in my test case I can create MockNewsBloc and inject it easily to the MainPage when it is under testing.

Answered By – Asis

Answer Checked By – Dawn Plyler (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.