错误状态:GetIt:类型为 <> 的对象/工厂未在 GetIt 内注册

问题描述 投票:0回答:2

我正在尝试将依赖注入与

get_it
包一起使用,以便进行单元测试。

我正在使用这些依赖项:

get_it: ^7.6.0
injectable_generator: ^2.1.6

我的

main
函数看起来像这样:

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

  // [...]
}

我等待

test
环境的设置,我等待它是
allReady

该文件使用

injection.dart
,其中包含
setup()
函数:

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 dev = 'dev';
  static const prod = 'prod';
  static const test = 'test';
}

如您所见,我想使用

AuthRepository
进行生产(将调用数据库),或
TestAuthRepository
进行单元测试(不会调用数据库)。

我在这里声明了这些类,在一个文件中

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

      // ... (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<int> createNewUser({required String login, required String email, required String password}) {
    return Future.value(2);
  }
}

目前,测试函数

createNewUser
仅返回2。

我在这里启动我的测试:

void main() {

  AuthController authController = AuthController();

  test('Registration success', () async {

    int response = await authController.register(
      login: 'test',
      email: '[email protected]',
      password: 'Testing193!',
      passwordConfirmation: 'Testing193!',
    );
    expect(response, 1);
  });
  
  // ...
}

这个测试需要

authController.register()
,在这里:

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

    // [...]

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

我尝试使用

IAuthRepository
检索
getIt
实例。

但是,当我启动测试时,我收到此错误:

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.<fn>

我以为我注册了我的

IAuthRepository
课程,但它不起作用。怎样才能注册呢?

dart testing dependency-injection get-it
2个回答
1
投票

我终于成功了。

问题是:在

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 protected]',
      password: 'Testing193!',
      passwordConfirmation: 'Testing193!',
    );
    expect(response, 1);
  });
}

setupGetIt()
功能与
setup()
相同(我将其重命名为更清晰),它负责注册我需要的每个课程。

我在

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

我还删除了我实现的类顶部的所有

@Injectable()
注释,因为不需要它们。


0
投票

我们需要更改服务定位器:

首先我们需要注册服务/存储库,然后用它注册商店/提供商,如下所示。

final getIt = GetIt.instance;

Future<void> setUpLocator() async {
// Register Repositories:
getIt.registerSingleton<SwitchRepo>(SwitchRepo());

// Register Stores with Repositories:
getIt.registerSingleton<SwitchStore>(SwitchStore(getIt<SwitchRepo>()));
}
© www.soinside.com 2019 - 2024. All rights reserved.