Kotlin 如何用模拟服务替换Ktor路由测试中的Koin服务注入
我想对使用Koin注入服务的Ktor路由进行测试。在我的测试中,我正在努力模拟Ktor路由使用的服务 这是Ktor应用程序.kt文件Kotlin 如何用模拟服务替换Ktor路由测试中的Koin服务注入,kotlin,mocking,mockito,ktor,koin,Kotlin,Mocking,Mockito,Ktor,Koin,我想对使用Koin注入服务的Ktor路由进行测试。在我的测试中,我正在努力模拟Ktor路由使用的服务 这是Ktor应用程序.kt文件 @kotlin.jvm.JvmOverloads fun Application.module(testing: Boolean = false) { install(Locations) { } // Suppressed code installKoin(listOf(dependencyInjectionModule))
@kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
install(Locations) {
}
// Suppressed code
installKoin(listOf(dependencyInjectionModule))
routing {
val eventService by inject<EventService>()
get("/issues/{issueNumber}/events") {
val issue = call.parameters["issueNumber"]
val issueNumber = parseInt(issue)
call.respond(eventService.getEventsByIssueNumber(issueNumber))
}
}
// Suppressed code
}
class ApplicationTest {
private val eventDtoList = listOfNotNull(
EventDto(1, "opened", "2019-03-24T21:40:18Z", 1 ),
EventDto(2, "closed", "2019-03-28T21:40:18Z", 1 )
)
@Test
fun testGettingEventsByExistingIssueNumber() {
withTestApplication({ module(testing = true) }) {
stopKoin()
handleRequest(HttpMethod.Get, "/issues/1/events").apply {
val eventService:EventService = mock {
onBlocking { getEventsByIssueNumber(any()) } doReturn eventDtoList
}
val resultList = Gson().fromJson(response.content, Array<EventDto>::class.java).asList()
assertEquals(response.status(), HttpStatusCode.OK)
assertThat(resultList).hasSize(2)
}
}
}
}
我得到一个例外:
2019-05-08 11:51:40:881 (KOIN)::[e] Error while resolving instance for class 'com.service.EventService' - error: org.koin.error.NoBeanDefFoundException: No compatible definition found for type 'EventService'. Check your module definition
org.koin.error.NoBeanDefFoundException: No compatible definition found for type 'EventService'. Check your module definition
at org.koin.core.bean.BeanRegistry.retrieveDefinition(BeanRegistry.kt:113)
at org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1.invoke(InstanceRegistry.kt:87)
at org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1.invoke(InstanceRegistry.kt:36)
at org.koin.core.time.DurationKt.measureDuration(Duration.kt:8)
at org.koin.core.instance.InstanceRegistry.proceedResolution(InstanceRegistry.kt:84)
at org.koin.core.instance.InstanceRegistry.resolve(InstanceRegistry.kt:63)
at org.koin.core.instance.InstanceRegistry.resolve$default(InstanceRegistry.kt:48)
at com.jaya.octovevent.ApplicationKt$module$4$$special$$inlined$inject$1.invoke(KtorRoutingExt.kt:112)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at com.jaya.octovevent.ApplicationKt$module$4$2.invokeSuspend(Application.kt:76)
at com.ApplicationKt$module$4$2.invoke(Application.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
at io.ktor.features.StatusPages$interceptCall$2.invokeSuspend(StatusPages.kt:94)
at io.ktor.features.StatusPages$interceptCall$2.invoke(StatusPages.kt)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:91)
at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:180)
at io.ktor.features.StatusPages.interceptCall(StatusPages.kt:93)
at io.ktor.features.StatusPages$Feature$install$2.invokeSuspend(StatusPages.kt:133)
at io.ktor.features.StatusPages$Feature$install$2.invoke(StatusPages.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:157)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:23)
at io.ktor.routing.Routing.executeResult(Routing.kt:148)
at io.ktor.routing.Routing.interceptor(Routing.kt:29)
at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:93)
at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
at io.ktor.features.ContentNegotiation$Feature$install$1.invokeSuspend(ContentNegotiation.kt:63)
at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:157)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:23)
at io.ktor.server.testing.TestApplicationEngine$2.invokeSuspend(TestApplicationEngine.kt:265)
at io.ktor.server.testing.TestApplicationEngine$2.invoke(TestApplicationEngine.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:157)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:23)
at io.ktor.server.testing.TestApplicationEngine$handleRequest$pipelineJob$1.invokeSuspend(TestApplicationEngine.kt:263)
at |b|b|b(Coroutine boundary.|b(|b)
at io.ktor.features.StatusPages.interceptCall(StatusPages.kt:93)
at io.ktor.features.StatusPages$Feature$install$2.invokeSuspend(StatusPages.kt:133)
at io.ktor.routing.Routing.executeResult(Routing.kt:148)
at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:93)
at io.ktor.features.ContentNegotiation$Feature$install$1.invokeSuspend(ContentNegotiation.kt:63)
at io.ktor.server.testing.TestApplicationEngine$2.invokeSuspend(TestApplicationEngine.kt:265)
at io.ktor.server.testing.TestApplicationEngine$handleRequest$pipelineJob$1.invokeSuspend(TestApplicationEngine.kt:263)
at kotlinx.coroutines.DeferredCoroutine.await$suspendImpl(Builders.common.kt:98)
at io.ktor.server.testing.TestApplicationEngine$handleRequest$1.invokeSuspend(TestApplicationEngine.kt:129)
Caused by: org.koin.error.NoBeanDefFoundException: No compatible definition found for type 'EventService'. Check your module definition
at org.koin.core.bean.BeanRegistry.retrieveDefinition(BeanRegistry.kt:113)
at org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1.invoke(InstanceRegistry.kt:87)
at org.koin.core.instance.InstanceRegistry$proceedResolution$$inlined$synchronized$lambda$1.invoke(InstanceRegistry.kt:36)
at org.koin.core.time.DurationKt.measureDuration(Duration.kt:8)
at org.koin.core.instance.InstanceRegistry.proceedResolution(InstanceRegistry.kt:84)
at org.koin.core.instance.InstanceRegistry.resolve(InstanceRegistry.kt:63)
at org.koin.core.instance.InstanceRegistry.resolve$default(InstanceRegistry.kt:48)
at com.ApplicationKt$module$4$$special$$inlined$inject$1.invoke(KtorRoutingExt.kt:112)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at com.ApplicationKt$module$4$2.invokeSuspend(Application.kt:76)
at com.ApplicationKt$module$4$2.invoke(Application.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
at io.ktor.features.StatusPages$interceptCall$2.invokeSuspend(StatusPages.kt:94)
at io.ktor.features.StatusPages$interceptCall$2.invoke(StatusPages.kt)
at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:91)
at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:180)
at io.ktor.features.StatusPages.interceptCall(StatusPages.kt:93)
at io.ktor.features.StatusPages$Feature$install$2.invokeSuspend(StatusPages.kt:133)
at io.ktor.features.StatusPages$Feature$install$2.invoke(StatusPages.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:157)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:23)
at io.ktor.routing.Routing.executeResult(Routing.kt:148)
at io.ktor.routing.Routing.interceptor(Routing.kt:29)
at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:93)
at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
at io.ktor.features.ContentNegotiation$Feature$install$1.invokeSuspend(ContentNegotiation.kt:63)
at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:157)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:23)
at io.ktor.server.testing.TestApplicationEngine$2.invokeSuspend(TestApplicationEngine.kt:265)
at io.ktor.server.testing.TestApplicationEngine$2.invoke(TestApplicationEngine.kt)
at io.ktor.util.pipeline.SuspendFunctionGun.loop(PipelineContext.kt:278)
at io.ktor.util.pipeline.SuspendFunctionGun.access$loop(PipelineContext.kt:63)
at io.ktor.util.pipeline.SuspendFunctionGun.proceed(PipelineContext.kt:137)
at io.ktor.util.pipeline.SuspendFunctionGun.execute(PipelineContext.kt:157)
at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:23)
at io.ktor.server.testing.TestApplicationEngine$handleRequest$pipelineJob$1.invokeSuspend(TestApplicationEngine.kt:263)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:238)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742)
我知道Koin找不到EventService实现,因为我已经停止了它(Koin)。那么,我如何用我的模拟服务取代Koin注入
提前感谢如果您试图设置代码进行测试/模拟,而不是试图研究Koin的功能,那么我所做的就是分解这些功能,例如:
fun Application.module(testing: Boolean = false) {
val todoService: TodoService by inject()
moduleWithDependencies(eventService)
}
fun Application.moduleWithDependencies(eventService: EventService) {
install(Routing) {
eventApi(eventService)
}
}
eventApi有路由,然后我可以独立测试它
这里有一个示例(不是很完整)问题是您正在
应用程序.module()内部启动Koin
最好在调用Application.module()
之前启动Koin。因此,您可以在生产和测试环境中初始化不同的依赖项
以下是如何启动生产环境:
fun main(args: Array<String>) {
val appEnvironment = commandLineEnvironment(args)
startKoin { modules(initAppModule(appEnvironment.config)) }
embeddedServer(Netty, appEnvironment).start(true)
}
fun testApp(test: TestApplicationEngine.() -> Unit) {
withApplication(createTestEnvironment {
config = HoconApplicationConfig(ConfigFactory.load("application.conf"))
startKoin { modules(initTestAppModule(config)) }
}, {
}, test)
val koin = KoinContextHandler.get()
stopKoin() // Stop koin after test
}
请参见此处的示例:
还有:你读过下面的内容吗?是的,我试过了,但没用。谢谢你的建议!你能允许访问那个存储库吗?我将试着模拟hereHi@JamesFreitas,抱歉离开了一段时间。现在已经公开了
fun testApp(test: TestApplicationEngine.() -> Unit) {
withApplication(createTestEnvironment {
config = HoconApplicationConfig(ConfigFactory.load("application.conf"))
startKoin { modules(initTestAppModule(config)) }
}, {
}, test)
val koin = KoinContextHandler.get()
stopKoin() // Stop koin after test
}