My application is set up to load up the database immediately the server starts to run
with createdAtStart = true
val dbModule = module {
single(createdAtStart = true) {
Db(
driverClassName = "org.h2.Driver", jdbcURL = "jdbc:h2:file:./build/db"
)
}
when running the server normally, i do not need to manually inject the database anywhere to initialize it as it is done automatically and dependents on the db object obtain
also, the db used for testing is an in-memory database and is inject in unit test using koin easily
factory(qualifier = named("test")) { params ->
Db(
driverClassName = "org.h2.Driver",
jdbcURL = "jdbc:h2:mem:${params.get<String>()};DB_CLOSE_DELAY=-1"
)
}
the question
in testing the application as a whole, i.e the server routes using ktor's testApplication
, the default database is injected directly and I cannot inject the test db.
// test is empty because i realised i can't inject my test db
class ApplicationTest: KoinTest {
@Test
fun testRoot() = testApplication {
val response = client.get("/")
assertEquals(HttpStatusCode.OK, response.status)
}
}
I'm thinking there's a flaw in my app design and file structure and all that as this is my first time using ktor
how do i get the right db into the test application
I had to restructure my code base a bit.
The main database is no longer eargerly created
// koin.kt
val dbModule = module {
single {
Db(
driverClassName = "org.h2.Driver", jdbcURL = "jdbc:h2:file:./build/db"
)
}
factory(qualifier = named("test")) { params ->
Db(
driverClassName = "org.h2.Driver",
jdbcURL = "jdbc:h2:mem:${params.get<String>()};DB_CLOSE_DELAY=-1"
)
}
}
Dependency injection and database configuration were separated into different modules and used based on a testing flag on the main module
// application.kt
fun Application.di() {
install(Koin) {
slf4jLogger()
modules(dbModule)
}
}
fun Application.configureDb() {
val db: Db by inject()
TransactionManager.defaultDatabase = db.database // this line isn't really need as exposed uses last open db connection
}
fun Application.main(testing: Boolean = false) {
if (!testing) {
di()
configured()
}
}
class ApplicationTest : KoinTest {
private lateinit var db: Db
@BeforeEach
fun `setup db`() {
db = get {
parametersOf("")
}
TransactionManager.defaultDatabase = db.database
}
@Test
fun testRoot() = testApplication {
application {
module(testing = true)
}
environment {
config =
ApplicationConfig("test_application.yaml") // loads environment variables for test
val response = client. Get("/")
assertEquals(HttpStatusCode.OK, response.status)
}
companion object {
@JvmStatic
@BeforeAll
fun `start koin`(): Unit {
startKoin {
modules(dbModule)
}
}
}
}
see these links for more clarification on some methods used
How to setup Koin in Ktor using testApplication()
?