1

我正在尝试编写一个注入服务依赖项的 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(); 
} 

然后在我的测试类中使用注入服务:

@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来自HikariModuleguice 注入的类的服务在测试中失败。

我的目标是允许以下列方式编写测试:

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

在测试中注入服务依赖项的正确方法是什么?我更喜欢重用 guice 模块,MainClassApplicationUnderTest而不是创建自己的模块并覆盖它们。

4

1 回答 1

2

在与这个问题斗争了一段时间并得到了 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();
        }));
    }
};

事实证明,有一个漂亮的方法可以启动应用程序。所以当注入类时,我们会知道它Registry不会为空,我们可以注入类。

protected <T> T inject(final Class<T> classOf) {
    aut.getAddress();
    return appRegistry.get(classOf);
}

然后在测试类中,我们可以简单地注入注册表中存在的任何类。

final UserService userService = inject(UserService.class);
// OR
final DataSource dataSource = inject(DataSource.class);
于 2017-10-21T09:49:10.563 回答