Problem
I write widget tests for pages. They require BLoC for rendering. get_it is used for dependency injection. The providers use asynchronous functions, so I created a "fake" bloc that returns static data for the widget tests.
For some reason, the bloc injected from get_it doesn't work.
My code
So I have a test:
void main() {
setUpAll(() async {
SharedPreferences.setMockInitialValues({});
await getIt.reset();
await setup();
getIt.registerFactory(
() => FakeScheduleBloc( // Stack trace says I have an error in this line
getSchedule: getIt(),
getActiveGroup: getIt(),
getGroups: getIt(),
setActiveGroup: getIt(),
getDownloadedSchedules: getIt(),
deleteSchedule: getIt(),
getScheduleSettings: getIt(),
setScheduleSettings: getIt(),
),
);
});
testWidgets('Go to News frome Home', (WidgetTester tester) async {
await tester.pumpWidget(
_getFullContext(const HomeNavigatorScreen(isFirstRun: false)));
await tester.tap(find.byKey(WidgetKeys.bottomBarNews));
await tester.pumpAndSettle();
expect(find.byType(NewsScreen), findsOneWidget);
});
}
A context builder:
Widget _getFullContext(Widget child) {
return getAdvancedContext(child, [
BlocProvider<ScheduleBloc>(create: (context) => getIt<FakeScheduleBloc>()), // Stack trace says I have an error in this line
BlocProvider<HomeNavigatorBloc>(
create: (context) => getIt<HomeNavigatorBloc>()),
]);
}
Widget getAdvancedContext(
Widget child, List<BlocProviderSingleChildWidget> providers) {
return MultiBlocProvider(
providers: providers,
child: AdaptiveTheme(
light: lightTheme,
dark: darkTheme,
initial: AdaptiveThemeMode.dark,
builder: (theme, darkTheme) => MaterialApp(
home: child,
),
),
);
}
A fake bloc:
// Fake bloc extends real one, but overrides mapEventToState
class FakeScheduleBloc extends ScheduleBloc {
FakeScheduleBloc({
/* some variables */
}) : super(
/* some variables */
);
@override
Stream<ScheduleState> mapEventToState(
ScheduleEvent event,
) async* {
yield SomeStaticData;
}
}
And a setup:
final getIt = GetIt.instance;
Future<void> setup() async {
// BloC / Cubit
getIt.registerFactory(
() => ScheduleBloc(
// There is an implementation of a real ScheduleBloc
),
);
getIt.registerFactory(() => HomeNavigatorBloc());
}
Errors
When I run tests, I see some errors.
Error while creating FakeScheduleBloc
Stack trace:
#0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:46:39)
...
#464 StackZoneSpecification._registerUnaryCallback.<anonymous closure> (package:stack_trace/src/stack_zone_specification.dart)
<asynchronous suspension>
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown building MediaQuery(MediaQueryData(size: Size(800.0, 600.0),
devicePixelRatio: 3.0, textScaleFactor: 1.0, platformBrightness: Brightness.light, padding:
EdgeInsets.zero, viewPadding: EdgeInsets.zero, viewInsets: EdgeInsets.zero, alwaysUse24HourFormat:
false, accessibleNavigation: false, highContrast: false, disableAnimations: false, invertColors:
false, boldText: false, navigationMode: traditional)):
GetIt: The compiler could not infer the type. You have to provide a type and optionally a name. Did
you accidentally do `var sl=GetIt.instance();` instead of var sl=GetIt.instance;
'package:get_it/get_it_impl.dart':
Failed assertion: line 333 pos 7: 'type != null || const Object() is! T'
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following StateError was thrown building MediaQuery(MediaQueryData(size: Size(800.0, 600.0),
devicePixelRatio: 3.0, textScaleFactor: 1.0, platformBrightness: Brightness.light, padding:
EdgeInsets.zero, viewPadding: EdgeInsets.zero, viewInsets: EdgeInsets.zero, alwaysUse24HourFormat:
false, accessibleNavigation: false, highContrast: false, disableAnimations: false, invertColors:
false, boldText: false, navigationMode: traditional)):
Bad state: Tried to read a provider that threw during the creation of its value.
The exception occurred during the creation of type ScheduleBloc.
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following message was thrown:
Multiple exceptions (2) were detected during the running of the current test, and at least one was
unexpected.
My goal
I want to create a fake bloc and inject it in get_it to test widgets, that require bloc.
Why do I use get_it?
I use it because the widgets use BlocBuilder, which means I need to inherit from it to create my fake bloc. ScheduleBloc has a giant constructor that depends on usecases that are also injected in get_it, so I can't get rid of get_it.