Reputation: 121
Ktor (kotlin web framework) has an awesome testable mode where http requests can be wrapped in unit tests. They give a nice example of how to test a GET endpoint here, however I'm having trouble with an http POST.
I tried this but the post params don't seem to be added to the request:
@Test
fun testSomePostThing() = withTestApplication(Application::myModule) {
with(handleRequest(HttpMethod.Post, "/api/v2/processing") {
addHeader("content-type", "application/x-www-form-urlencoded")
addHeader("Accept", "application/json")
body = "param1=cool7¶m2=awesome4"
}) {
assertEquals(HttpStatusCode.OK, response.status())
val resp = mapper.readValue<TriggerResponse>(response.content ?: "")
assertEquals(TriggerResponse("cool7", "awesome4", true), resp)
}
}
Anyone have any ideas?
Upvotes: 5
Views: 5993
Reputation: 1155
For those using the alternate .apply
to verify results, you can prepend the body before the test call
withTestApplication({ module(testing = true) }) {
handleRequest(HttpMethod.Post, "/"){
setBody(...)
}.apply {
assertEquals(HttpStatusCode.OK, response.status())
assertEquals("HELLO WORLD!", response.content)
}
}
Upvotes: 3
Reputation: 17691
For those reading it nowadays, back in 2018 receiveParameters()
method was added for such cases. You can use it as:
install(Routing) {
post("/api/v2/processing") {
val params = call.receiveParameters()
println(params["param1"]) // Prints cool7
...
}
}
Also it's worth noting that request construction in the example could be further improved nowadays:
// Use provided consts, not strings
addHeader(HttpHeaders.ContentType, ContentType.Application.FormUrlEncoded.toString())
// Convenient method instead of constructing string requests
setBody(listOf("param1" to "cool7", "param2" to "awesome4").formUrlEncode())
Upvotes: 2
Reputation: 3105
call.parameters also works for post routes.
get("api/{country}") {
val country = call.parameters["country"]!!
...
}
This will give you whatever is passed in the uri after api.
call.receive is for the body of a request.
Upvotes: 1
Reputation: 121
Ok dumb mistake, I'll post it here in case this saves somebody else from wasting time ;) The unit test was actually catching a real problem (thats what they're for I guess) In my routing I was using:
install(Routing) {
post("/api/v2/processing") {
val params = call.parameters
...
}
}
However that only works for 'get' params. Post params need:
install(Routing) {
post("/api/v2/processing") {
val params = call.receive<ValuesMap>()
...
}
}
Upvotes: 2