使用 Guice 注入对 Ratpack 服务器进行 JUnit 测试
JUnit testing of Ratpack server with Guice injection
我正在尝试编写一个注入了服务依赖项的 JUnit 测试。
protected MainClassApplicationUnderTest aut = new MainClassApplicationUnderTest(App.class) {
@Override
protected void addImpositions(final ImpositionsSpec impositions) {
impositions.add(UserRegistryImposition.of(appRegistry -> {
// Allow modifying Injector in tests
return appRegistry.join(Guice.registry(injector));
}));
}
};
private Injector injector = com.google.inject.Guice.createInjector(new Module());
@Before
public void setup () {
injector.injectMembers(this);
}
@After
public void tearDown() {
aut.close();
}
然后在我的测试中使用注入服务 classes:
@Inject
private UserService userService;
在我开始使用 HikariModule
将持久性添加到我的应用程序之前,它一直运行良好。现在 Guice 注册表创建有点复杂:
.join(Guice.registry(b -> b
.module(HikariModule.class, hikariConfig -> {
final String dbUrl = System.getenv("JDBC_DATABASE_URL");
hikariConfig.setJdbcUrl(dbUrl);
})
.module(Module.class)
.bind(DbMigrator.class)
).apply(r))
因为我的注册表现在由多个模块组成,如果我有一个服务依赖于 DataSource
class 来自 HikariModule
guice 注入在测试中失败。
我的目标是允许以下列方式编写测试:
@Inject // <- not required can be done in @Before method
private UserService userService; // <- Inject it somehow from Application under test
@Test
public void testUser() {
final Result<User, String> userResult = userService.create(new User.Registration());
final ReceivedResponse res = aut.getHttpClient().get("/users/" + user.userId);
assertEquals(200, res.getStatusCode());
}
在测试中注入服务依赖项的正确方法是什么?我非常喜欢重用 MainClassApplicationUnderTest
中的 guice 模块,而不是创建自己的模块并覆盖它们。
在与这个问题斗争了很长一段时间后,在 Ratpack slack 的帮助下,我设法解决了这个问题。
首先我们需要在本地变量中捕获我们的应用程序注册表。
private Registry appRegistry;
protected MainClassApplicationUnderTest aut = new MainClassApplicationUnderTest(App.class) {
@Override
protected void addImpositions(final ImpositionsSpec impositions) {
impositions.add(UserRegistryImposition.of(r -> {
appRegistry = r;
return Registry.empty();
}));
}
};
原来有一个启动应用程序的绝妙方法。所以当注入 class 时,我们会知道 Registry
不会为空,我们可以注入 classes.
protected <T> T inject(final Class<T> classOf) {
aut.getAddress();
return appRegistry.get(classOf);
}
然后在测试 classes 中,我们可以简单地注入注册表中存在的任何 class。
final UserService userService = inject(UserService.class);
// OR
final DataSource dataSource = inject(DataSource.class);
我正在尝试编写一个注入了服务依赖项的 JUnit 测试。
protected MainClassApplicationUnderTest aut = new MainClassApplicationUnderTest(App.class) {
@Override
protected void addImpositions(final ImpositionsSpec impositions) {
impositions.add(UserRegistryImposition.of(appRegistry -> {
// Allow modifying Injector in tests
return appRegistry.join(Guice.registry(injector));
}));
}
};
private Injector injector = com.google.inject.Guice.createInjector(new Module());
@Before
public void setup () {
injector.injectMembers(this);
}
@After
public void tearDown() {
aut.close();
}
然后在我的测试中使用注入服务 classes:
@Inject
private UserService userService;
在我开始使用 HikariModule
将持久性添加到我的应用程序之前,它一直运行良好。现在 Guice 注册表创建有点复杂:
.join(Guice.registry(b -> b
.module(HikariModule.class, hikariConfig -> {
final String dbUrl = System.getenv("JDBC_DATABASE_URL");
hikariConfig.setJdbcUrl(dbUrl);
})
.module(Module.class)
.bind(DbMigrator.class)
).apply(r))
因为我的注册表现在由多个模块组成,如果我有一个服务依赖于 DataSource
class 来自 HikariModule
guice 注入在测试中失败。
我的目标是允许以下列方式编写测试:
@Inject // <- not required can be done in @Before method
private UserService userService; // <- Inject it somehow from Application under test
@Test
public void testUser() {
final Result<User, String> userResult = userService.create(new User.Registration());
final ReceivedResponse res = aut.getHttpClient().get("/users/" + user.userId);
assertEquals(200, res.getStatusCode());
}
在测试中注入服务依赖项的正确方法是什么?我非常喜欢重用 MainClassApplicationUnderTest
中的 guice 模块,而不是创建自己的模块并覆盖它们。
在与这个问题斗争了很长一段时间后,在 Ratpack slack 的帮助下,我设法解决了这个问题。
首先我们需要在本地变量中捕获我们的应用程序注册表。
private Registry appRegistry;
protected MainClassApplicationUnderTest aut = new MainClassApplicationUnderTest(App.class) {
@Override
protected void addImpositions(final ImpositionsSpec impositions) {
impositions.add(UserRegistryImposition.of(r -> {
appRegistry = r;
return Registry.empty();
}));
}
};
原来有一个启动应用程序的绝妙方法。所以当注入 class 时,我们会知道 Registry
不会为空,我们可以注入 classes.
protected <T> T inject(final Class<T> classOf) {
aut.getAddress();
return appRegistry.get(classOf);
}
然后在测试 classes 中,我们可以简单地注入注册表中存在的任何 class。
final UserService userService = inject(UserService.class);
// OR
final DataSource dataSource = inject(DataSource.class);