使用 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);