Test widget using the BLoC pattern
I had the exact same problem when testing a widget and was able to solve it. Here's the "Before Code" that didn't work and "After Code" that did the trick...
BEFORE CODE
Notice that when pumping the widget MaterialApp is set as the top most widget.
Future<Null> _buildRideCard(WidgetTester tester) async {
await tester.pumpWidget(MaterialApp( // top most widget
localizationsDelegates: [
AppLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
//some other stuff, irrelevant for this example
));
}
AFTER CODE
Notice how MaterialApp widget is now wrapped with BlocProvider and it's blocProviders property is given a list of Blocs that the widget test needs. This fixed my problem and now I don't have any context issues with the bloc in my widget test. Hope it helps ;)
Future<Null> _buildRideCard(WidgetTester tester) async {
await tester.pumpWidget(BlocProviderTree( // <- magic #1
blocProviders: [ <- magic #2
BlocProvider<RideDetailsBloc>(
bloc: RideDetailsBloc(_setupRidesRepo()))
],
child: MaterialApp(
localizationsDelegates: [
AppLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
//some other stuff, irrelevant for this example
),
));
}
jj.
Software Developer, Technology fan. https://www.jjerome.com
Updated on December 07, 2022Comments
-
jj. over 1 year
I have been learning Flutter/Dart and the BLoC Pattern. I used this article as my starting point: https://www.didierboelens.com/2018/08/reactive-programming---streams---bloc/
I have the bloc class and widget working, but I can't figure out how to test the widget. I'm using a
BlocProvider
as described in the article, but I can't figure out how to provide the widget with a mocked bloc class.If I have code like this:
@override Widget build(BuildContext context) { final ProfileBloc profileBloc = BlocProvider.of<ProfileBloc>(context); return Scaffold( body: Container( child: StreamBuilder<AuthModel>( stream: profileBloc.outAuthModel, initialData: null, builder: (BuildContext context, AsyncSnapshot<AuthModel> snapshot) { if (snapshot.hasData) { return buildProfilePage(context, snapshot.data.profile); } return buildStartPage(); }, ), )); }
I want to mock my ProfileBloc, but it is created in my build() function and requires context. How can I test this widget? I think I need a way to pass in a mocked ProfileBloc, but I can not figure out how to do it. I want to ensure that the widget behaves as intended.
-
jj. over 5 yearsThe article mentions sometimes needing to create the bloc locally, and using a StatefulWidget to leverage dispose. So I'll have to use a stateful widget anytime I want to test my widget? I guess I thought I'd be using this provider more often than a local object.
-
Conner over 5 yearsA provider isn't the way to go when doing an individual widget test, but it would probably be used in an integration test
-
David about 5 yearsI dont' get it. I have the same problem, but what @jj. posted there is the code from the actual widget, not the test. How do I provide a mocked bloc (ProfileBloc in this case) in my test? The widget will call
BlocProvider.of()
and I have no way to intercept that AFAIK.