https://kotlinlang.org logo
#ktor
Title
# ktor
b

bbaldino

06/15/2022, 10:00 PM
Is there a good pattern anyone uses to test mocking both successful and error responses from a server when testing a client? So you’d normally have something like:
Copy code
val mockHttpClient = HttpClient(MockEngine) {
    engine {
        addHandler { request -> {
            when (request.url.encodedPath) {
                "url1" -> respond(someSuccessResponse)
            }
        }
    }
}
val client = MyClient(mockHttpClient)
...
but I want to be able to test how
MyClient
handles different kinds of responses when hitting
url1
, but the mock engine config is fixed…is there a good way to be able to change it to simulate different responses?
I was digging around in the code and saw that it looks like
reuseHandlers
may be intended for this purpose. By setting this to false, you could make multiple calls to
addHandler
and have them each be used in succession. The API seems like it would be a bit awkward in practice, though, since there’s only access to that scope when creating the client, so you’d have to configure the responses in a certain way above and then test those scenarios in the same order below. I’m looking at a wrapper to install a dynamic handler that allows configuring the responses separately from the initial config.
a

Aleksei Tirman [JB]

06/16/2022, 6:35 AM
So do you want to add handlers outside of the config, like this?
Copy code
var handlers = mutableListOf<MockRequestHandler>()
val client = HttpClient(MockEngine) {
    engine {
        handlers = requestHandlers
        reuseHandlers = false
    }
}

handlers.add { request ->
    respondOk("1")
}

handlers.add { request ->
    respondOk("2")
}

client.get("/").bodyAsText().let { println(it) }
client.get("/").bodyAsText().let { println(it) }
This code doesn’t work right now because there is the check in the
MockEngine
’s constructor that throws an exception if there are no request handlers.
b

bbaldino

06/16/2022, 2:58 PM
I ended up doing this:
Copy code
private val handlers: MutableMap<Path, MockRequestHandler> = mutableMapOf()
    private val client: HttpClient = HttpClient(MockEngine) {
        block()
        engine {
            addHandler { request ->
                val path = Path(request.method, request.url.encodedPath)
                this@MockHttpClientWrapper.handlers[path]?.let { handler ->
                    handler(request)
                } ?: error("No handler installed for path $path")
            }
        }
    }
in a wrapper class, and then have an API to be able to add to
handlers
199 Views