kotlinunit-testingktorkoin

Test Ktor Application with Koin (not embedded)


I'm looking to properly test a Ktor application, which uses Koin and is specifically not using the embeddedServer method of creating the app. All solutions that I have found were either outdated or were using the embedded server. Here is a simplified version of my code:

Main.kt

fun main(args: Array<String>): Unit = EngineMain.main(args)

fun Application.koinModule() {
    install(Koin) {
        modules(myModule)
    }
}

fun Application.doOtherStuff() {
    val someSingleton by inject<SomeSingleton>()
    (...)
}

application.yaml:

ktor:
    deployment:
        port: 8080
    application:
        modules:
            - MainKt.koinModule
            - MainKt.doOtherStuff

My current solution does somewhat work, but feels hacky and spams KoinNotStartedException in the console:

Test.kt:

class MyTest : KoinTest {

    @AfterEach
    fun cleanup() {
        stopKoin()
    }

    @Test
    fun `mock koin module`() = testApplication {
        startKoin {
            modules(
                myModule,
                myMockModule, // override module with mocks
            )
        }
        environment {
            config = ApplicationConfig("application-test.yaml")
        }
        (...) // test code
    }
}

application-test.yaml

ktor:
    deployment:
        port: 8080
    application:
        modules: # same as application.yaml, but without koin module
            - MainKt.doOtherStuff

If there is an intended and more importantly documented way of testing Ktor with Koin, feel free to link it. Thank you!


Solution

  • I think your problem is that you are starting koin inside testApplication {} which already expects koin context to be up. To get ahead you should use KoinTestRule for junit4 or KoinTestExtension for junit5.

    class MyTest : KoinTest {
        companion object {
            @JvmField
            @RegisterExtension
            val koinTestExtension = KoinTestExtension.create {
                modules(myModule, myMockModule)
            }
        }
    
        @Test
        fun `test`() = testApplication {
            ...
        }
    }
    

    More detailes in koin docs https://insert-koin.io/docs/reference/koin-test/testing