get_it
get_it copied to clipboard
[Feature] Option for ignoreReassignment
Right now GetIt errors if we try to re-register a type. Optionally, there's an option to allow re-registration, but that will replace the first registered type with the second.
I'm looking for a third option that will just ignore any attempts to re-register an already registered type (hopefully silently).
This would be used exclusively for testing. Right now if we need to register a singleton that has side effects or real dependencies as a side effect of being created, there's not a good way to get around that in testing.
Contrived simple example: I've got class RealFoo extends IFoo that reaches out to a real database as part of being instantiated. I register this class a dependency during startup as part of my app's construction as GetIt.I.registerSingleton<IFoo>(RealFoo()). And my test calls app().startup() and then verifies that various things happened during startup.
I'd instead like to do something like this with my tests
setup() {
GetIt.I.ignoreReassignment = true;
}
test('the test', () {
GetIt.I.registerSingleton<IFoo>(FakeFoo());
// RealFoo attempts to be registered in here, but is now ignored as GetIt already has a registered `IFoo`
app().startup();
// verify stuff
}
This would make it so that when RealFoo is registered as part of creating App, it just gets ignored as I already registered FakeFoo and the test can then verify the other stuff that I actually care about.
why not just registering in setup?
Also ignoreReassignment could be marked as @visibleForTesting.
why not just registering in setup?
I have a setup function the runs at the beginning, but I want to reassign one of the singletons being created there. The only way I have is verbose, I need to pass nullable instances to setup, so I can verify if they are null or not. If they are not null, I use them, so this is how we can inject fake instances for tests. This very verbose and could be immensely simplified if we had a ignoreReassignmentForTesting.
Here's an example of what I have to do now:
@override
Future<void> setup({
Dio? dio,
ExampleRestDataSource? exampleRestDataSource,
PackageInfo? packageInfo,
ExampleRepository? ExampleRepository,
ExampleCubit? ExampleCubit,
}) async {
getIt
..registerSingleton(dio ?? Dio())
..registerSingleton(exampleRestDataSource ?? ExampleRestDataSource(getIt()))
..registerSingleton(packageInfo ?? await PackageInfo.fromPlatform())
..registerSingleton(exampleRepository ??
ExampleRepository(
exampleRestDataSource: getIt(),
packageInfo: getIt(),
))
..registerSingleton(exampleCubit ?? ExampleCubit(exampleRepository: getIt()));
}
why not just registering in setup?
Because that yields the same result as what I outlined above. If I moveGetIt.I.registerSingleton<IFoo>(FakeFoo()); into setup, the test is still going to blow up when I call app.startup because startup registers RealFoo. Right now we have to have suboptimal code in our production code so that we can conditionally register dependencies based on whether we're testing or not.
OK, I think I finally understood this issue the first time, my bad. We probably should call the option something like skipDoubleRegistrations
Implemented in V7.6.8