I created my first multiplatform example project, https://github.com/hantsy/cargotracker-regapp-kotlin-multiplatform
And use a shared
lib module to shake hands with the REST APIs.
In the shared
module, I tried to use ktor-client-mock
in the commonTest
sources to test the APIs, but it seems that it always uses the platform underlying HttpClient to call the remote rest API instead of the mocking engine in the tests. The exception indicated that it was trying to connect to the URL of the remote APIs.
The REST API-related client codes(in commonMain
) are similar to the following.
class HandlingReportClient(client: HttpClient) {
suspend fun submitReport(report: HandlingReport): HandlingResponse {
val baseUrl = getEnvVariable("HANDLING_REPORT_SERVICE_URL") ?: DEFAULT_BASE_URL
val response = client.request("$baseUrl/rest/handling/reports") {
method = HttpMethod.Get
contentType(ContentType.Application.Json)
accept(ContentType.Application.Json)
setBody(report)
}
return if (response.status == HttpStatusCode.OK) {
response.body(typeInfo<HandlingResponse.Success>())
} else {
response.body(typeInfo<HandlingResponse.Error>())
}
}
}
And the testing codes(in commonTest
):
class HandlingReportClientTest {
val report = HandlingReport(
completionTime = "1/10/2025 27:59",
trackingId = "AAA",
eventType = "LOAD",
unLocode = "CHSHA",
voyageNumber = "A0123"
)
@Test
fun `submit report`() = runTest {
val mockEngine = MockEngine { request ->
respond(
content = """""",
status = HttpStatusCode.Companion.OK,
headers = headersOf(HttpHeaders.ContentType, "application/json")
)
}
val client = HandlingReportClient(HttpClient(mockEngine))
val result = client.submitReport(report)
result is HandlingResponse.Success
assertEquals("OK", result.toString())
}
@Test
fun `submit report(with respond error)`() = runTest {
val mockEngine = MockEngine { request ->
respond(
content = """
{
"message":"err"
}
""".trimIndent(),
status = HttpStatusCode.Companion.BadRequest,
headers = headersOf(HttpHeaders.ContentType, "application/json")
)
}
val client = HandlingReportClient(HttpClient(mockEngine))
val result = client.submitReport(report)
result is HandlingResponse.Error
assertEquals("err", (result as HandlingResponse.Error).message)
}
}
The complete codes: https://github.com/hantsy/cargotracker-regapp-kotlin-multiplatform/tree/master/shared
I used an expect/actual
function to get the HttpClient
for different platforms. It seems when running the tests, the MockEngine
in the tests did not replace the one on the platform.
The problem is that in the shared/src/commonMain/kotlin/cargotracker/regapp/shared/HandlingReportClient.kt
file, the HTTP client instance used for making the requests is declared as a top-level property. The one that is passed for the HandlingReportClient
class constructor is unused.
To solve the problem, use the HTTP client defined in the class.