How to use get_it (flutter dependency injection) in the widget test?

Viewed 7751

When I use dependency injections in a project, my widget tests fails.

My error is as follows:

Testing started at 10:07 AM ...
C:\src\flutter\bin\flutter.bat --no-color test --machine --plain-name "Exist FloatingActionButton" test\features\announcement\presentation\widgets_test\announcement_widget_test.dart
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞══════════════════════'═════════════════════════════════════
The following assertion was thrown building _BodyBuilder:
No type AnnouncementBloc is registered inside GetIt.
Did you forget to pass an instance name?
(Did you accidentally do GetIt sl=GetIt.instance(); instead of GetIt sl=GetIt.instance;did you
forget to register it?)
'package:get_it/get_it_impl.dart':
Failed assertion: line 251 pos 14: 'instanceFactory != null'

The relevant error-causing widget was:
Scaffold
file:///C:/Projects/niaz-flutter/lib/features/announcement/presentation/pages/announcements_page.dart:15:12

When the exception was thrown, this was the stack:
#2 _GetItImplementation._findFactoryByNameOrType (package:get_it/get_it_impl.dart:251:14)
#3 _GetItImplementation.get (package:get_it/get_it_impl.dart:263:27)
#4 _GetItImplementation.call (package:get_it/get_it_impl.dart:288:12)
#5 new _AnnouncementsWidgetState (package:niaz/features/announcement/presentation/widgets/announcements_widget.dart:22:19)
#6 AnnouncementsWidget.createState (package:niaz/features/announcement/presentation/widgets/announcements_widget.dart:18:46)
#7 new StatefulElement (package:flutter/src/widgets/framework.dart:4600:25)
#8 StatefulWidget.createElement (package:flutter/src/widgets/framework.dart:896:38)
... Normal element mounting (19 frames)
#27 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3455:14)
#28 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5956:32)
... Normal element mounting (193 frames)
#221 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3455:14)
#222 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5956:32)
... Normal element mounting (255 frames)
#477 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3455:14)
#478 Element.updateChild (package:flutter/src/widgets/framework.dart:3220:20)
#479 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1132:16)
#480 RenderObjectToWidgetElement.update (package:flutter/src/widgets/binding.dart:1110:5)
#481 RenderObjectToWidgetElement.performRebuild (package:flutter/src/widgets/binding.dart:1124:7)
#482 Element.rebuild (package:flutter/src/widgets/framework.dart:4227:5)
#483 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2632:33)
#484 AutomatedTestWidgetsFlutterBinding.drawFrame (package:flutter_test/src/binding.dart:1016:18)
#485 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:284:5)
#486 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1113:15)
#487 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1052:9)
#488 AutomatedTestWidgetsFlutterBinding.pump. (package:flutter_test/src/binding.dart:889:9)
#491 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:72:41)
#492 AutomatedTestWidgetsFlutterBinding.pump (package:flutter_test/src/binding.dart:876:27)
#493 WidgetTester.pumpWidget. (package:flutter_test/src/widget_tester.dart:462:22)
#496 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:72:41)
#497 WidgetTester.pumpWidget (package:flutter_test/src/widget_tester.dart:459:27)
#498 main. (file:///C:/Projects/niaz-flutter/test/features/announcement/presentation/widgets_test/announcement_widget_test.dart:15:18)
#499 main. (file:///C:/Projects/niaz-flutter/test/features/announcement/presentation/widgets_test/announcement_widget_test.dart:14:45)
#500 testWidgets.. (package:flutter_test/src/widget_tester.dart:144:29)
#511 FakeAsync.flushMicrotasks (package:fake_async/fake_async.dart:192:32)
#512 AutomatedTestWidgetsFlutterBinding.runTest. (package:flutter_test/src/binding.dart:1109:17)
#513 AutomatedTestWidgetsFlutterBinding.runTest. (package:flutter_test/src/binding.dart:1097:35)
(elided 31 frames from class _AssertionError, dart:async, and package:stack_trace)

════════════════════════════════════════════════════════════════════════════════════════════════════

Test failed. See exception logs above.

The test description was: Exist FloatingActionButton

4 Answers

This will depend on how you initially setup get_it in your project.

To fix this issue for my setup I simply called the method that registers my dependencies in the setUpAll method of the test file.

So I have a file in the root of the lib folder that registers my dependencies:

final getIt = GetIt.instance;

void setupDependencyInjection() {
  GetIt.instance.registerSingleton<SomeServiceInterface>(SomeService());
}
 

The setupDependencyInjection method is called before the runApp app method in the main.dart file.

For testing you simply need to call the same method in the setUpAll method of your test file.

void main() {
  setUpAll(() {
    setupDependencyInjection();
  });


  testWidgets('Some test description', (WidgetTester tester) async {

    final widget = TestWidget();

    await tester.pumpWidget(widget);
  });
}

No type AnnouncementBloc is registered inside GetIt. Did you forget to pass an instance name?

You need to use [getIt.registerFactory< AnnouncementBloc >(() => AnnouncementBloc());] in your test mode firstly.

For example, I use Service Locator Pattern in my app and will getIt all blocs and repositories there, so I set a bool [testing] in serviceLocator like:

Future<void> serviceLocator({bool testing = false}) async {
    if (testing){
        // unit/widget/bloc test
        getIt.registerFactory<AccountBloc>(() => AccountBloc(accountRepository: getIt()));
        getIt.registerFactory<AccountRepository>(() => AccountRepositoryMock());

    } else {
        // run app
        getIt.registerFactory<AccountBloc>(() => AccountBloc(accountRepository: getIt()));
        getIt.registerFactory<AccountRepository>(() => AccountRepositoryFactory(dioProvider: getIt()));
    }
}

Also, you need to assign [testing] as true in your test file, like:

void main(){
  serviceLocator(testing: true);

  testWidgets('try widget test', (WidgetTester tester) async {
     .
     .
     .
    });
}

Your question is very unclear (I'd want to see your test code), but I think that I can help you.

You can set the GetIt.instance inside the setUp() or setUpAll() and register your mocked BLoC, like this:

class MockMyBloc extends MockBloc<MyStates> implements MyBloc {}

void main() {

    MyBloc bloc;
    MockMyBloc mockMyBloc;
   
    setUp(() {
        mockMyBloc = MockMyBloc();
        final dependency_injection = GetIt.instance;
        dependency_injection.registerFactory<MyBloc>(() => mockMyBloc);

        bloc = dependency_injection<MyBloc>();
    });

    //tests
}

First Initalize your dependency container and then unregister previously registered dependency and then register with mockdependency

import 'package:your_app/injection_container.dart' as di;  //import your depencency/ioc container

class MockMyCubit extends MockCubit<MyState> implements MyCubit {}

void main() {
  late MockMyCubit mockMyCubit;

   setUpAll(() async {
      di.init();   //to register your dependencies
      mockMyCubit = MockMyCubit(); //create instance of mockCubit
      await di.sl.unregister<MyCubit>();//unregister previously registered cubit
      di.sl.registerFactory<MyCubit>(() => mockMyCubit); //register mockCubit
    });

  tearDownAll(() {
  di.sl.reset(dispose: true);
  });

  testWidgets('', (teser) async {
 //testyour widget here
 }

}

Related