I’m struggling a little with testing JSON in a pos...
# ktor
j
I’m struggling a little with testing JSON in a post request. It fails within the Ktor tests, but if I send a direct HTTP request in via curl or whatever, it works fine. Totally stumped - any help would be much appreciated.
My test is pretty light-weight at the moment
Copy code
withTestApplication({ configureRouting() }) {
            with(handleRequest(<http://HttpMethod.Post|HttpMethod.Post>, "/preview", ) {
                addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
                setBody(Json.encodeToString(Entity(name="test", description="A test description")))
            }) {
                assertEquals(HttpStatusCode.OK, response.status())
            }
        }
And the Route definition even more so
Copy code
post("/preview") {
            val config = call.receive<Entity>()
            call.respondText(call.receiveText())
        }
It fails
Cannot transform this request's content to <package>.Entity
Interestingly, if I swap out
call.receive<Entity>()
with
Json.decodeFromString<Entity>(call.receiveText())
it seems to work. I’d have thought they were functionally similar.
rubber duck 1
l
I've had issues with the JSON feature before. I usually just switch it out to Json.decodeFromString and wait. Usually it's because of a problem in my code, and call.receive works once I fix it. It's much easier to debug this way.
a
Could you please share the code for a complete test cause the following code works as expected?
Copy code
import io.ktor.application.*
import io.ktor.features.*
import io.ktor.http.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.serialization.*
import io.ktor.server.testing.*
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.junit.Test
import kotlin.test.assertEquals

class SomeTest {
    @OptIn(ExperimentalSerializationApi::class)
    @Test
    fun test(): Unit = withTestApplication({ configureRouting() }) {
        application.install(ContentNegotiation) {
            json()
        }

        with(handleRequest(<http://HttpMethod.Post|HttpMethod.Post>, "/preview", ) {
            addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
            setBody(Json.encodeToString(Entity(name="test", description="A test description")))
        }) {
            assertEquals(HttpStatusCode.OK, response.status())
            assertEquals("A test description", response.content)
        }
    }
}

fun Application.configureRouting() {
    routing {
        post("/preview") {
            val config = call.receive<Entity>()
            call.respondText(config.description)
        }
    }
}


@Serializable
data class Entity(val name: String, val description: String)
j
Thank you so much, that code works great. I hadn’t installed the
ContentNegotiation
in the test.