Reputation: 1334
Currently I write a small demo-app which uses Ktor as its Application Environment and Kodein as the Dependency Injection Framework.
During the initialization of the Application I do import some modules, one of those I would like to replace during the initialization of the Integration Tests:
fun Application.module(testing: Boolean = false) {
logger.debug { "Starting main" }
restModule()
di {
bind<Json>() with singleton {
Json {
...
}
}
import(persistenceModule)
}
In the test, I would like to use a different persistenceModule, say eg. a MemoryModule. My tests are initialized like:
fun start() {
val configPath = ClassLoader.getSystemResource("application-acceptanceTest.conf").file
engine = embeddedServer(CIO, commandLineEnvironment(arrayOf("-config=$configPath")))
engine.start()
val disposable = engine.environment.monitor.subscribe(ApplicationStarted) { application: Application ->
started = true
}
while (!started) {
Thread.sleep(10)
}
disposable.dispose()
}
I have tried already to call
engine.application.di
but this gives me (quite obviously) only access to the Ktor Feature, which is already initialized. Is anything like this possible at all?
Upvotes: 1
Views: 991
Reputation: 544
Kodein-DI allows you to override dependencies. Regarding the following interface:
interface Repository {
fun save()
fun find()
}
You can have a production implementation, included in its own DI module:
class PersistenceRepository : Repository {
/* implementation */
}
val persistenceModule = DI.Module("persistenceModule") {
bind<Repository>() with singleton { PersistenceRepository() }
}
and also a test implementation of that same interface:
class MemoryRepository : Repository {
/* implementation */
}
val memoryModule = DI.Module("memoryModule") {
bind<Repository>(overrides = true) with singleton { MemoryRepository() }
}
Note the overrides
parameter that needs to be explicit.
You can pass a DI container to your Ktor function:
val mainDI = DI {
import(persistenceModule)
}
fun Application.main(di: DI) {
di { extend(di) }
}
And extend the mainDI
in your tests, to override the proper bindings with the memoryModule
:
class ApplicationTest {
val testDI = DI {
extend(mainDI)
import(memoryModule, allowOverride = true)
}
@Test
fun myTest() {
withTestApplication({ main(testDI) })
// ...
}
}
Upvotes: 1