Bad state: GetIt: Object/factory with type <> is not registered inside GetIt

huangapple go评论53阅读模式
英文:

Bad state: GetIt: Object/factory with type <> is not registered inside GetIt

问题

I am trying to use dependency injection with the get_it package in order to make unit tests.

我正在尝试使用get_it包进行依赖注入,以便进行单元测试。

I am using these dependencies:

我正在使用以下依赖项:

get_it: ^7.6.0
injectable_generator: ^2.1.6

My main function looks like this:

我的main函数如下所示:

void main(List<String> args) async {
  // Configure injection
  await setup(Env.test);
  await getIt.allReady();

  // [...]
}

I wait for the setup with the test environment, and I wait for it to be allReady.

我等待使用test环境进行设置,并等待它准备好。

The file uses injection.dart, which contains the setup() function:

该文件使用包含setup()函数的injection.dart

GetIt getIt = GetIt.instance;

@InjectableInit(preferRelativeImports: false)
setup(String env) {
  getIt.init();
  if (env == Env.test) {
    getIt.registerLazySingleton<IAuthRepository>(() => TestAuthRepository());
  } else {
    getIt.registerLazySingleton<IAuthRepository>(() => AuthRepository());
  }
}

abstract class Env {
  static const prod = 'prod';
  static const test = 'test';
}

As you can see, I want to use AuthRepository for production (which will call a database) or TestAuthRepository for unit tests (which will not call the database).

正如你所看到的,我想在生产中使用AuthRepository(它将调用数据库)或在单元测试中使用TestAuthRepository(它不会调用数据库)。

I have declared these classes in a file called auth_repository.dart:

我在名为auth_repository.dart的文件中声明了这些类:

abstract class IAuthRepository {
  Future<int> createNewUser({
    required String login,
    required String email,
    required String password,
  });
}

@Injectable(as: IAuthRepository, env: [Env.prod])
class AuthRepository extends BaseRepository implements IAuthRepository {
  @override
  Future<int> createNewUser({
    required String login,
    required String email,
    required String password,
  }) async {
    try {
      final connection = await getDatabaseConnection();

      // ...(进行数据库调用)...

      return 1;
    } catch (exception) {
      print(exception);
      return -1;
    }
  }
}

@Injectable(as: IAuthRepository, env: [Env.test])
class TestAuthRepository extends BaseRepository implements IAuthRepository {
  @override
  Future<int> createNewUser({
    required String login,
    required String email,
    required String password,
  }) {
    return Future.value(2);
  }
}

For now, the testing function createNewUser will only return 2.

目前,测试函数createNewUser将只返回2。

I am launching my test here:

我在这里启动我的测试:

void main() {
  AuthController authController = AuthController();

  test('Registration success', () async {
    int response = await authController.register(
      login: 'test',
      email: 'email@mail.com',
      password: 'Testing193!',
      passwordConfirmation: 'Testing193!',
    );
    expect(response, 1);
  });
  
  // ...
}

This test calls the authController.register() method, which is defined as follows:

这个测试调用了authController.register()方法,其定义如下:

Future<int> register({
  required String login,
  required String email,
  required String password,
  required String passwordConfirmation,
}) async {
  // [...]

  IAuthRepository authRepository = getIt.get<IAuthRepository>();
  return await authRepository.createNewUser(
    login: login,
    email: email,
    password: password,
  );
}

I try to retrieve an IAuthRepository instance with getIt.

我尝试使用getIt获取一个IAuthRepository实例。

However, when I launch my tests, I get this error:

然而,当我运行我的测试时,我收到以下错误消息:

00:00 +0 -1: Registration success [E]                                                                                                                     
  Bad state: GetIt: Object/factory with type IAuthRepository is not registered inside GetIt. 
  (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 12:19                 throwIfNot
  package:get_it/get_it_impl.dart 395:5                 _GetItImplementation._findFactoryByNameAndType
  package:get_it/get_it_impl.dart 423:29                _GetItImplementation.get
  package:toast/controllers/auth_controller.dart 31:44  AuthController.register
  test/controllers/auth_controller_test.dart 23:41      main.&lt;fn&gt;

I thought I registered my IAuthRepository class; however, it does not work. How can I register it?

我以为我已经注册了我的IAuthRepository类,但是它不起作用。我该如何注册它?

英文:

I am trying to use dependency injection with get_it package, in order to make unit tests.

I am using these dependencies :

get_it: ^7.6.0
injectable_generator: ^2.1.6

My main function looks like this :

void main(List&lt;String&gt; args) async {
  // Configure injection
  await setup(Env.test);
  await getIt.allReady();

  // [...]
}

I wait for the setup with the test environment, and I wait for it to be allReady.

The file uses injection.dart, which contains the setup() function :

GetIt getIt = GetIt.instance;

@InjectableInit(preferRelativeImports: false)
setup(String env) {
  getIt.init();
  if (env == Env.test) {
    getIt.registerLazySingleton&lt;IAuthRepository&gt;(() =&gt; TestAuthRepository());
  } else {
    getIt.registerLazySingleton&lt;IAuthRepository&gt;(() =&gt; AuthRepository());
  }
}

abstract class Env {
  // static const dev = &#39;dev&#39;;
  static const prod = &#39;prod&#39;;
  static const test = &#39;test&#39;;
}

As you can see, I want to use AuthRepository for production (will call a database), or TestAuthRepository for unit tests (will not call the database).

I declared theses class here, in a file auth_repository.dart :

abstract class IAuthRepository {
  Future&lt;int&gt; createNewUser({
    required String login,
    required String email,
    required String password,
  });
}

@Injectable(as: IAuthRepository, env: [Env.prod])
class AuthRepository extends BaseRepository implements IAuthRepository {

  @override
  Future&lt;int&gt; createNewUser({
    required String login,
    required String email,
    required String password,
  }) async {
    try {
      final connection = await getDatabaseConnection();

      // ... (make the database call) ...

      return 1;
    } catch (exception) {
      print(exception);
      return -1;
    }
  }
}

@Injectable(as: IAuthRepository, env: [Env.test])
class TestAuthRepository extends BaseRepository implements IAuthRepository {

  @override
  Future&lt;int&gt; createNewUser({required String login, required String email, required String password}) {
    return Future.value(2);
  }
}

For now, the testing function createNewUser will only return 2.

I am launching my test here :

void main() {

  AuthController authController = AuthController();

  test(&#39;Registration success&#39;, () async {

    int response = await authController.register(
      login: &#39;test&#39;,
      email: &#39;email@mail.com&#39;,
      password: &#39;Testing193!&#39;,
      passwordConfirmation: &#39;Testing193!&#39;,
    );
    expect(response, 1);
  });
  
  // ...
}

This test calls for authController.register(), which is here :

  Future&lt;int&gt; register({
    required String login,
    required String email,
    required String password,
    required String passwordConfirmation,
  }) async {

    // [...]

    // IAuthRepository authRepository = getIt&lt;IAuthRepository&gt;();
    IAuthRepository authRepository = getIt.get&lt;IAuthRepository&gt;();
    return await authRepository.createNewUser(
      login: login,
      email: email,
      password: password,
    );
  }

I try to retrieve an IAuthRepository instance with getIt.

However, when I am launching my tests, I get this error :

00:00 +0 -1: Registration success [E]                                                                                                                     
  Bad state: GetIt: Object/factory with type IAuthRepository is not registered inside GetIt. 
  (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 12:19                 throwIfNot
  package:get_it/get_it_impl.dart 395:5                 _GetItImplementation._findFactoryByNameAndType
  package:get_it/get_it_impl.dart 423:29                _GetItImplementation.get
  package:toast/controllers/auth_controller.dart 31:44  AuthController.register
  test/controllers/auth_controller_test.dart 23:41      main.&lt;fn&gt;

I thought I registered my IAuthRepository class, however it does not work. How can I register it ?

答案1

得分: 1

Here is the translated content:

我终于让它工作了。

问题是这样的:setup() 函数注册了我所需的所有类实现,但它在 main() 函数中被调用(是的,这是我自己的疏忽...)。

然而,由于单元测试是针对每个类单独启动的,因此 main() 函数从未被调用。

所以,我的测试现在看起来像这样:

void main() {

  setUpAll(() {
    setupGetIt(Env.test);
  });

  tearDownAll(() {
    unregisterGetIt();
  });

  AuthController authController = AuthController();

  test('Registration success', () async {
    int response = await authController.register(
      login: 'test',
      email: 'email@mail.com',
      password: 'Testing193!',
      passwordConfirmation: 'Testing193!',
    );
    expect(response, 1);
  });
}

setupGetIt() 函数与 setup() 相同(我将其重命名以更清晰),它负责注册我需要的每个类。

我在 setUpAll() 函数中调用它,以便在所有测试之前注册它。
请注意,我还添加了一个 unregisterGetIt() 函数,它基本上只调用 getIt.reset() 来注销每个已注册的类。它在 tearDownAll() 中调用,这在所有测试之后被调用。

我还删除了我实现的类顶部的所有 @Injectable() 注释,因为它们不再需要。

英文:

I finally made it work.

Here was the problem : The setup() function, which registered all the class implementations I needed, was called in the main() function (yes, that IS silly from me...).

However, as unit tests are launched specifically to each class, the main() function was never invoked.

So, my test now looks like this :

void main() {

  setUpAll(() {
    setupGetIt(Env.test);
  });

  tearDownAll(() {
    unregisterGetIt();
  });

  AuthController authController = AuthController();

  test(&#39;Registration success&#39;, () async {
    int response = await authController.register(
      login: &#39;test&#39;,
      email: &#39;email@mail.com&#39;,
      password: &#39;Testing193!&#39;,
      passwordConfirmation: &#39;Testing193!&#39;,
    );
    expect(response, 1);
  });
}

The setupGetIt() function is the same as setup() (I renamed it to be more clear), it takes care of registering every class I need.

I call it in a setUpAll() function, in order to register it before all the tests.
Note that I also added a unregisterGetIt() function, which basically only calls getIt.reset() to unregister every registered class. It is called in tearDownAll(), which is called after all tests.

I also removed all the @Injectable() annotation on top of my implemented class, as they are not needed.

huangapple
  • 本文由 发表于 2023年6月13日 16:06:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76462865.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定