Testing Http Client (MockEngine)
Ktor exposes a MockEngine
for the HttpClient. This engine allows simulating HTTP calls without actually connecting to the endpoint. It allows to set a code block, that can handle the request and generates a response.
This engine is defined in the class io.ktor.client.engine.mock.MockEngine
in the artifact io.ktor:ktor-client-mock:$ktor_version,io.ktor:ktor-client-mock-jvm:$ktor_version,io.ktor:ktor-client-mock-js:$ktor_version,io.ktor:ktor-client-mock-native:$ktor_version
.
dependencies {
api "io.ktor:ktor-client-mock:$ktor_version"
api "io.ktor:ktor-client-mock-jvm:$ktor_version"
api "io.ktor:ktor-client-mock-js:$ktor_version"
api "io.ktor:ktor-client-mock-native:$ktor_version"
}
dependencies {
testImplementation("io.ktor:ktor-client-mock:$ktor_version")
testImplementation("io.ktor:ktor-client-mock-jvm:$ktor_version")
testImplementation("io.ktor:ktor-client-mock-js:$ktor_version")
testImplementation("io.ktor:ktor-client-mock-native:$ktor_version")
}
<project>
...
<dependencies>
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-client-mock</artifactId>
<version>${ktor.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-client-mock</artifactId>
<version>${ktor.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-client-mock</artifactId>
<version>${ktor.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-client-mock</artifactId>
<version>${ktor.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Usage
The usage is straightforward: the MockEngine class has a method addHandler
in MockEngineConfig
, that receives a block/callback that will handle the request. This callback receives an HttpRequest
as a parameter, and must return a HttpResponseData
. There are many helper methods to construct the response.
Full API description and list of helper methods could be found here.
A sample illustrating this:
val client = HttpClient(MockEngine) {
engine {
addHandler { request ->
when (request.url.fullUrl) {
"https://example.org/" -> {
val responseHeaders = headersOf("Content-Type" to listOf(ContentType.Text.Plain.toString()))
respond("Hello, world", headers = responseHeaders)
}
else -> error("Unhandled ${request.url.fullUrl}")
}
}
}
}
private val Url.hostWithPortIfRequired: String get() = if (port == protocol.defaultPort) host else hostWithPort
private val Url.fullUrl: String get() = "${protocol.name}://$hostWithPortIfRequired$fullPath"