With ktor 2.3.12, we have some tests that use `Tes...
# ktor
x
With ktor 2.3.12, we have some tests that use
TestApplicationCall
instances. They do something like this to create them:
Copy code
val environment = createTestEnvironment { }
val application = Application(environment)
val call = TestApplicationCall(
    application = application,
    coroutineContext = coroutineContext
)
call.request.addHeader("X-Zaphod-Heads", "2")

// test code that uses the `ApplicationCall` goes here
After upgrading to 3.0.0, this code no longer works. We can't create an
Application
using
Application(environment)
, and
TestApplicationCall
needs an
Application
. The tests themselves actually just need
ApplicationCall
instances. The only thing
TestApplicationCall
has that we use that isn't also in
ApplicationCall
is
request.addHeader
(ie:
TestApplicationReqest.addHeader
on the
request
property.) What's the right way to do this with ktor 3.0.0?
a
The right way is to rewrite the tests to use the
testApplication
method or the
ApplicationTestBuilder
(https://ktor.io/docs/server-testing.html). Here is an example:
Copy code
@Test
fun test() = runTest {
    val builder = ApplicationTestBuilder().apply {
        application {
            routing {
                get("/") {
                    call.response.header("custom", "value")
                    call.respond(HttpStatusCode.OK)
                }
            }
        }
    }

    val response = builder.client.get("/")
    assertEquals(response.headers["custom"], "value")
}
x
This particular test isn't trying to send requests to an application and then make assertions about the response.
We have a function that we use in `CallLoggingConfig.format`:
Copy code
fun callLogFormatter(
    call: ApplicationCall,
    clock: () -> Long
): String {
    ...
}

...

install(CallLogging) {
    ...
    val clock = ::getTimeMillis
    clock(clock)
    format { call -> callLogFormatter(call, clock) }
We have some tests of
callLogFormatter
that: 1. create an
ApplicationCall
with various request properties (method, headers, path, etc.), response properties (eg: status code) and attributes (eg: CallStartTime) 2. pass the call to
callLogFormatter
3. assert that the result of
callLogFormatter
is what we expect With ktor 2.x we just directly created a
TestApplicationCall
, which made it fairly easy to construct an
ApplicationCall
we could pass to
callLogFormatter
without having to go through routing or other complications. How can we do that with ktor 3.0.0?
a
Unfortunately, the
testApplication
API doesn't allow creating a separate
ApplicationCall
object. You can use the following code to test the
callLogFormatter
:
Copy code
@Test
fun test() = testApplication {
    routing {
        get {
            call.response.header("custom", "value")
            callLogFormatter(call) {
                123
            }

            // Make assertion
        }
    }

    client.get("/")
}
I've created an issue to address this limitation.
o
Here is a workaround you could try to use to get an instance of
Application
:
Copy code
@Test
fun test() = testApplication {
    lateinit var application: Application
    application { application = this }
    startApplication()
    
    val call = TestApplicationCall(
        application = application,
        coroutineContext = coroutineContext
    )
}
x
Thank you both! @Aleksei Tirman [JB], is there a way to capture all requests in the
testApplication
? That is, instead of:
Copy code
get { /* response setup and assertions */ }
is there an alternative to
get
that routes all HTTP methods?