get_it icon indicating copy to clipboard operation
get_it copied to clipboard

[Feature] Option for ignoreReassignment

Open dmrickey opened this issue 2 years ago • 3 comments
trafficstars

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.

dmrickey avatar Jul 17 '23 16:07 dmrickey

why not just registering in setup?

escamoteur avatar Aug 31 '23 08:08 escamoteur

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()));
  }

feinstein avatar Nov 20 '23 00:11 feinstein

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.

dmrickey avatar Dec 15 '23 19:12 dmrickey

OK, I think I finally understood this issue the first time, my bad. We probably should call the option something like skipDoubleRegistrations

escamoteur avatar Mar 23 '24 12:03 escamoteur

Implemented in V7.6.8

escamoteur avatar Apr 03 '24 08:04 escamoteur