jean
10/14/2021, 7:05 AMprivate val jsonResponse = """
{
"offset": 0,
"limit": 20,
"available": 104,
"items": [
{
"type": "news type",
"title": "news title",
"image": "news image",
"link": "news link",
"date": "1621807201000"
}
]
}
""".trimIndent()
When I parse it manually with Json.decodeFromString<NewsList>(jsonResponse)
I get my NewsList
object without any issues, but when I run my unit test with a MockEngine
returning the json as a string for any request, I end up with the following error :
kotlinx.serialization.json.internal.JsonDecodingException: Expected start of the array '[', but had 'EOF' instead
JSON input: .....ink": "news link",
"date": "1621807201000"
}
]
}
What am I doing wrong here?Aleksei Tirman [JB]
10/14/2021, 12:56 PMjean
10/14/2021, 1:26 PMprivate val jsonResponse = """
{
"offset": 0,
"limit": 20,
"available": 104,
"items": [
{
"type": "news type",
"title": "news title",
"image": "news image",
"link": "news link",
"date": "1621807201000"
}
]
}
""".trimIndent()
@Test
fun `get news from api should succeed`() = runTest {
val response = Json.decodeFromString<NewsList>(jsonResponse)
assertEquals(0, response.offset.value)
assertEquals(20, response.limit.value)
assertEquals(104, response.available.value)
}
But not this :
@Test
fun `get news from api should succeed`() = runTest {
val engine = MockEngine { request ->
respond(
content = ByteReadChannel(jsonResponse),
status = HttpStatusCode.OK,
headers = headersOf(HttpHeaders.ContentType, "application/json")
)
}
val result = ApiClient(engine).client.get<HttpResponse>("/") {
parameter("offset", 0)
parameter("limit", 20)
}
val body = result.receive<String>()
val news = Json.decodeFromString<NewsList>(body)
assertEquals(
NewsList(
offset = Offset(0),
limit = Limit(20),
available = Available(104),
items = Json.decodeFromString(jsonResponse)
), news
)
}
Aleksei Tirman [JB]
10/14/2021, 1:34 PMNewsList
class.jean
10/14/2021, 1:53 PMtypealias NewsList = ListWrapper<News>
@Serializable
data class ListWrapper<T>(
val offset: Offset,
val limit: Limit,
val available: Available,
val items: List<T>
)
Aleksei Tirman [JB]
10/14/2021, 2:08 PMUnexpected JSON token at offset 12: Expected start of the object '{', but had ' ' instead
because Offset
is a class but integer value (0
) is present in JSON.jean
10/14/2021, 2:10 PM@JvmInline
@Serializable
value class Offset(val value: Int)
But the issue is that it works in one case and not the other, so I would assume it’s not due to the json source?jean
10/14/2021, 2:16 PMcommonTest
jean
10/14/2021, 2:19 PMval news = Json.decodeFromString<NewsList>(body)
and run it manually in the debugger inspector, I can see the object is correctly created. The test fail the moment I resume itDavid Soller
10/14/2021, 3:01 PMNewsList(
offset = Offset(0),
limit = Limit(20),
available = Available(104),
items = Json.decodeFromString(jsonResponse)
), news
As it looks like in that MockEngine
test jsonResponse
might be treated as both a NewsList
and List<News>
e.g. the items =
section. Which would match with the original error you posted
kotlinx.serialization.json.internal.JsonDecodingException: Expected start of the array '[', but had 'EOF' instead
JSON input: .....ink": "news link",
e.g. items
wants a [...]
but you my be giving it a {...}
Either way best of luck!jean
10/15/2021, 6:01 AMDavid Soller
10/15/2021, 12:29 PM