Hi, I struggle with some testing for Koin in combi...
# koin
d
Hi, I struggle with some testing for Koin in combination with Ktor 3 server. Is it possible to write JVM Unit Tests for Ktor Server with koin-ktor and replace the injected dependencies? My current understanding: • The normal unit test way for Koin is to call startKoin in the test and then inject different (mock) implementations • With koin-ktor the Koin plugin handles the start of Koin inside the Ktor server internally. So there's no need to call startKoin in the Unit Test I tried to use
loadKoinModules()
, but that didn't work. See minimal code example in the thread. Is it possible to test that way? Is there another approach to do that?
My example with Koin Ktor and testing a Ktor Server. It always cals the "real" production implementation instead of the mock provided by mockk.
Copy code
class MinimalTest {
    private val experienceRepository = mockk<ExperienceRepository>()

    private val koinTestModule = module {
        single<ExperienceRepository> { experienceRepository }
    }

    @Test
    fun minimalTest() = testApplication {
        val experience = listOf(
            Experience(0, LocalDateTime.now(), 1, "reason1"),
            Experience(1, LocalDateTime.now(), 2, "reason2")
        )
        coEvery { experienceRepository.getExperience() } returns experience

        application {
            // The module extension function calls install(Koin) and
            // also injects the ExperienceRepository
            module()

            // Use the mocked ExperienceRepository instead
            loadKoinModules(koinTestModule)
        }

        // Internally the Ktor Server use the routing plugin and
        // then access the data with the ExperienceRepository.
        // It should use the mocked ExperienceRepository, but uses the production one
        val response = client.get(EXPERIENCE.fullResourcePath)
        val actual = Json.decodeFromString(ExperienceDTO.serializer(), response.bodyAsText())
        assert(actual.entries.isNotEmpty())
    }
}
d
Were you able to figure it out?
d
I've realized that it couldn't work because I already injected the repo in the
Application.module()
function and therefore
loadKoinModules
provides the mock, but it's never used. Due Koin issues I can't inject in Route extension function where I needed the repository provided with Koin. Therefore, I did hand over the modules as parameter ListModule in Application.module(). For production only the product module(s), for testing production + the koinTestModule that overrides the repo with the mockk. That works because when handing over multiple modules in Koin existing definitions of one module can be overridden by another.