Issue
I use KTor and Kotlin Serialization library in my android project, along with mockk and junit.jupiter for unit testing. I've encountered some problem when mocking ktor's suspend
function readText()
. The written unit test tests that initErrorMessage()
function returns correct error message.
Test class:
class ErrorTest {
private val errorMessage = "objectId must be provided."
private val errorCode = 2689
private val correctResponseJson = "{\"code\":$errorCode,\"message\":\"$errorMessage\"}"
// ResponseException class is from ktor library
private val exceptionMock: ResponseException = mockk(relaxed = true)
@Test
fun `initErrorMessage should return correct error message`() = runTest {
coEvery { exceptionMock.response.readText() } returns correctResponseJson // <-- here is the Error occurs
val expectedError = errorMessage
val actualError = initErrorMessage(exceptionMock)
assertEquals(expectedError, actualError)
}
}
Method to test:
suspend fun initErrorMessage(cause: ResponseException): String {
return try {
val body = cause.response.readText()
val jsonSerializer = JsonObject.serializer()
val jsonObj = Json.decodeFromString(jsonSerializer, body)
jsonObj["message"].toString()
} catch (e: Exception) {
""
}
}
During execution of the first line in the test method I get an Error:
Premature end of stream: expected 1 bytes
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 com.example.android.http.error.ErrorTest$initErrorMessage should return correct error message$1$1.invokeSuspend(ErrorTest.kt:37)
at com.example.android.http.error.ErrorTest$initErrorMessage should return correct error message$1$1.invoke(ErrorTest.kt)
at com.example.android.http.error.ErrorTest$initErrorMessage should return correct error message$1$1.invoke(ErrorTest.kt)
at io.mockk.impl.eval.RecordedBlockEvaluator$record$block$2$1.invokeSuspend(RecordedBlockEvaluator.kt:28)
at io.mockk.impl.eval.RecordedBlockEvaluator$record$block$2$1.invoke(RecordedBlockEvaluator.kt)
at io.mockk.InternalPlatformDsl$runCoroutine$1.invokeSuspend(InternalPlatformDsl.kt:20)
How to mock this suspend
method readText()
without an Error?
Solution
It turned out that the function readText()
hasn't been mocked properly.
It is an extension function on HttpResponse
and it has to be mocked using mockkStatic
function, for example like this:
@BeforeEach
fun setup() {
mockkStatic(HttpResponse::readText)
}
setup()
will be executed before each @Test
, because it is marked with @BeforeEach
annotation.
Answered By - Sergey
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.