我正在尝试将依赖注入与
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
课程,但它不起作用。怎样才能注册呢?
我终于成功了。
问题是:在
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()
注释,因为不需要它们。
我们需要更改服务定位器:
首先我们需要注册服务/存储库,然后用它注册商店/提供商,如下所示。
final getIt = GetIt.instance;
Future<void> setUpLocator() async {
// Register Repositories:
getIt.registerSingleton<SwitchRepo>(SwitchRepo());
// Register Stores with Repositories:
getIt.registerSingleton<SwitchStore>(SwitchStore(getIt<SwitchRepo>()));
}