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.
1. dependencies {
2. api "io.ktor:ktor-client-mock:$ktor_version"
3. api "io.ktor:ktor-client-mock-jvm:$ktor_version"
4. api "io.ktor:ktor-client-mock-js:$ktor_version"
5. api "io.ktor:ktor-client-mock-native:$ktor_version"
6. }
1. dependencies {
2. testImplementation("io.ktor:ktor-client-mock:$ktor_version")
3. testImplementation("io.ktor:ktor-client-mock-jvm:$ktor_version")
4. testImplementation("io.ktor:ktor-client-mock-js:$ktor_version")
5. testImplementation("io.ktor:ktor-client-mock-native:$ktor_version")
6. }
1. <project>
2. ...
3. <dependencies>
4. <dependency>
5. <groupId>io.ktor</groupId>
6. <artifactId>ktor-client-mock</artifactId>
7. <version>${ktor.version}</version>
8. <scope>test</scope>
9. </dependency>
10. <dependency>
11. <groupId>io.ktor</groupId>
12. <artifactId>ktor-client-mock</artifactId>
13. <version>${ktor.version}</version>
14. <scope>test</scope>
15. </dependency>
16. <dependency>
17. <groupId>io.ktor</groupId>
18. <artifactId>ktor-client-mock</artifactId>
19. <version>${ktor.version}</version>
20. <scope>test</scope>
21. </dependency>
22. <dependency>
23. <groupId>io.ktor</groupId>
24. <artifactId>ktor-client-mock</artifactId>
25. <version>${ktor.version}</version>
26. <scope>test</scope>
27. </dependency>
28. </dependencies>
29. </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:
1. val client = HttpClient(MockEngine) {
2. engine {
3. addHandler { request ->
4. when (request.url.fullUrl) {
5. "https://example.org/" -> {
6. val responseHeaders = headersOf("Content-Type" to listOf(ContentType.Text.Plain.toString()))
7. respond("Hello, world", headers = responseHeaders)
8. }
9. else -> error("Unhandled ${request.url.fullUrl}")
10. }
11. }
12. }
13. }
15. private val Url.hostWithPortIfRequired: String get() = if (port == protocol.defaultPort) host else hostWithPort
16. private val Url.fullUrl: String get() = "${protocol.name}://$hostWithPortIfRequired$fullPath"
