微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用 mockk 对象和 junit.jupiter 测试挂起函数?

如何解决如何使用 mockk 对象和 junit.jupiter 测试挂起函数?

我正在使用 Ktor 构建 Kotlin Slack Event API 应用程序,但在测试我的函数时遇到了一些问题。

我有一个名为 SlackApi 的类,它将使用 KTor 客户端从 Slack API 请求用户列表。

import com.google.gson.Gson
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.request.HttpRequestBuilder
import io.ktor.client.request.get
import io.ktor.client.request.header
import io.ktor.client.request.url
import io.ktor.client.statement.HttpResponse
import io.ktor.client.statement.readText
import io.ktor.http.HttpHeaders

data class SlackUserProfile(val real_name: String,val display_name: String,val real_name_normalized:String,val display_name_normalized: String)
data class SlackUser(val id: String,val profile: SlackUserProfile)
data class UserListResponse(val ok: Boolean,val members: List<SlackUser>)

class SlackApi(
    private val client: HttpClient = HttpClient(CIO),private val gson: Gson = Gson(),private val bot_user_oauth_token: String = "bot-oauth-token-goes-here",) {
    suspend fun getUsers(): UserListResponse {
        var builder = HttpRequestBuilder()
        builder.url("https://slack.com/api/users.list")
        builder.header(HttpHeaders.Authorization,"Bearer ${bot_user_oauth_token}")
        val response = client.get<HttpResponse>(builder)
        return gson.fromJson(response.readText(),UserListResponse::class.java)
    }
}

我有一个(非工作)尝试进行测试:

import com.google.gson.Gson
import io.ktor.client.HttpClient
import io.ktor.client.request.HttpRequestBuilder
import io.ktor.client.request.get
import io.ktor.client.statement.HttpResponse
import io.ktor.client.statement.readText
import io.mockk.coEvery
import io.mockk.mockk
import kotlinx.coroutines.test.runBlockingTest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.nested
import org.junit.jupiter.api.Test

class SlackApiTest {
    private val client:HttpClient = mockk()
    private val bottoken: String = "123456-bottoken"
    private val testObj = SlackApi(
        client = client,bot_user_oauth_token = bottoken,)

    @nested
    inner class GetUsers {

        @Test
        fun `returns the list of users from the client`() = runBlockingTest {
            val expectedUsers = listof(SlackUser("blarg",SlackUserProfile("name","name","name")))
            val jsonUsers:String = Gson().toJson(expectedUsers)

            var httpResponse:HttpResponse = mockk()
            coEvery { httpResponse.readText() } returns jsonUsers

            val builder = slot<HttpRequestBuilder>()

            coEvery { client.get<HttpResponse>(capture(builder))
            } coAnswers {
                assertEquals("https://slack.com/api/users.list",builder.captured.url)
                assertEquals("Bearer ${bottoken}",builder.captured.headers.get(HttpHeaders.Authorization))
                httpResponse
            }

            val allUsers = testObj.getUsers()

            assertEquals(expectedUsers,allUsers.members)
        }
    }
}

但这不起作用,这可能是因为我对这种培训应该如何运作存在一些误解。相反,我收到了一个堆栈跟踪错误

java.io.EOFException: Premature end of stream: expected 1 bytes

    at io.ktor.utils.io.core.StringsKt.prematureEndOfStream(Strings.kt:492)
    at io.ktor.utils.io.core.internal.UnsafeKt.prepareReadHeadFallback(Unsafe.kt:78)
    at io.ktor.utils.io.core.internal.UnsafeKt.prepareReadFirstHead(Unsafe.kt:61)
    at io.ktor.utils.io.charsets.CharsetJVMKt.decode(CharsetJVM.kt:556)
    at io.ktor.utils.io.charsets.EncodingKt.decode(Encoding.kt:103)
    at io.ktor.utils.io.charsets.EncodingKt.decode$default(Encoding.kt:101)
    at io.ktor.client.statement.HttpStatementKt.readText(HttpStatement.kt:173)
    at io.ktor.client.statement.HttpStatementKt.readText$default(HttpStatement.kt:168)
    at my.slackbot.SlackApiTest$GetUsers$returns the list of users from the client$1$1.invokeSuspend(SlackApiTest.kt:33)
    at my.slackbot.SlackApiTest$GetUsers$returns the list of users from the client$1$1.invoke(SlackApiTest.kt)
    at io.mockk.impl.eval.RecordedBlockEvaluator$record$block$2$1.invokeSuspend(RecordedBlockEvaluator.kt:26)
    at io.mockk.impl.eval.RecordedBlockEvaluator$record$block$2$1.invoke(RecordedBlockEvaluator.kt)
    at io.mockk.InternalPlatformdsl$runcoroutine$1.invokeSuspend(InternalPlatformdsl.kt:20)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.dispatchedTask.run(dispatchedTask.kt:106)
    at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
    at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:86)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:61)
    at kotlinx.coroutines.BuildersKt.runBlocking(UnkNown Source)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt)
    at kotlinx.coroutines.BuildersKt.runBlocking$default(UnkNown Source)
    at io.mockk.InternalPlatformdsl.runcoroutine(InternalPlatformdsl.kt:19)
    at io.mockk.impl.eval.RecordedBlockEvaluator$record$block$2.invoke(RecordedBlockEvaluator.kt:26)
    at io.mockk.impl.eval.RecordedBlockEvaluator$enhanceWithRethrow$1.invoke(RecordedBlockEvaluator.kt:74)
    at io.mockk.impl.recording.JvmAutoHinter.autoHint(JvmAutoHinter.kt:23)
    at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:36)
    at io.mockk.impl.eval.EveryBlockEvaluator.every(EveryBlockEvaluator.kt:30)
    at io.mockk.MockKDsl.internalCoEvery(API.kt:98)
    at io.mockk.MockKKt.coEvery(MockK.kt:116)
    at my.slackbot.SlackApiTest$GetUsers$returns the list of users from the client$1.invokeSuspend(SlackApiTest.kt:33)
    at my.slackbot.SlackApiTest$GetUsers$returns the list of users from the client$1.invoke(SlackApiTest.kt)
    at kotlinx.coroutines.test.TestBuildersKt$runBlockingTest$deferred$1.invokeSuspend(TestBuilders.kt:50)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.dispatchedTask.run(dispatchedTask.kt:106)
    at kotlinx.coroutines.test.TestCoroutinedispatcher.dispatch(TestCoroutinedispatcher.kt:50)
    at kotlinx.coroutines.internal.dispatchedContinuationKt.resumeCancellableWith(dispatchedContinuation.kt:305)
    at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
    at kotlinx.coroutines.BuildersKt__Builders_commonKt.startCoroutineImpl(Builders.common.kt:192)
    at kotlinx.coroutines.BuildersKt.startCoroutineImpl(UnkNown Source)
    at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:145)
    at kotlinx.coroutines.BuildersKt__Builders_commonKt.async(Builders.common.kt:91)
    at kotlinx.coroutines.BuildersKt.async(UnkNown Source)
    at kotlinx.coroutines.BuildersKt__Builders_commonKt.async$default(Builders.common.kt:84)
    at kotlinx.coroutines.BuildersKt.async$default(UnkNown Source)
    at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest(TestBuilders.kt:49)
    at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest$default(TestBuilders.kt:45)
    at my.slackbot.SlackApiTest$GetUsers.returns the list of users from the client(SlackApiTest.kt:28)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:212)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:208)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
    at com.intellij.junit5.junit5IdeaTestRunner.startRunnerWithArgs(junit5IdeaTestRunner.java:71)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)

我需要能够测试此函数的行为,但我找不到任何详细说明我正在尝试执行的操作或什至可能的文档。

解决方法

您可以使用 Ktor 的 MockEngine 来测试响应转换和请求标头:

@Test
fun `returns the list of users from the client`(): Unit = runBlocking {
    val expectedUsers = listOf(SlackUser("blarg",SlackUserProfile("name","name","name")))
    val expectedResponse = UserListResponse(true,expectedUsers)
    val jsonResponse: String = Gson().toJson(expectedResponse)

    val client = HttpClient(MockEngine) {
        engine {
            addHandler { request ->
                assertEquals(request.url.toString(),"https://slack.com/api/users.list")
                assertEquals(request.headers["Authorization"],"Bearer 123456-bottoken")
                respond(content = jsonResponse)
            }
        }
    }

    val testObj = SlackApi(
        client = client,bot_user_oauth_token = "123456-bottoken",)

    assertEquals(expectedUsers,testObj.getUsers().members)
}

不幸的是,由于您描述的奇怪的 Premature end of stream: expected 1 bytes 错误以及 {{1} 中存在顶级内联方法,我没有找到使用 mockk 库解决您的问题的方法}} 类。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。