I am trying to write a JUnit test with service dependencies being injected.
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();
}
and then using injected services in my test classes:
@Inject
private UserService userService;
This was working fine until I started adding persistence to my app with HikariModule
. Now Guice registry creation is a bit more complex:
.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))
Because my registry now consists of multiple modules if I have a service that depends on DataSource
class coming from HikariModule
guice injection fails in tests.
My goal is to allow writing tests in the following fashion:
@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());
}
What is the right approach of injecting service dependencies in tests? I would very much prefer reusing guice modules from MainClassApplicationUnderTest
rather than creating my own and overriding them.
After quite some time battling with this issue and help from Ratpack slack I managed to pull this off.
First of all we need to capture our application registry in the local variable.
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();
}));
}
};
It turns out there is a nifty method that starts the application. So when injecting the class we will know that Registry
will not be null and we can inject classes.
protected <T> T inject(final Class<T> classOf) {
aut.getAddress();
return appRegistry.get(classOf);
}
Then in test classes we can simply inject any class that is present in the registry.
final UserService userService = inject(UserService.class);
// OR
final DataSource dataSource = inject(DataSource.class);