Richard Hajdu
07/19/2023, 7:04 PMAleksei Tirman [JB]
07/20/2023, 7:01 AMRichard Hajdu
07/20/2023, 7:26 AMMockEngine
in tests, but the example for configuring engines in multiplatform projects says that the engine should be defined only by the platform and not by the client implementation, but this way I cannot exchange the engine in tests.Richard Hajdu
07/20/2023, 7:32 AMMockEngine
in tests?Aleksei Tirman [JB]
07/20/2023, 2:18 PMRichard Hajdu
07/20/2023, 2:23 PMAleksei Tirman [JB]
07/20/2023, 2:24 PMRichard Hajdu
07/20/2023, 2:25 PMRichard Hajdu
07/24/2023, 6:25 AMNo transformation found: class io.ktor.utils.io.ByteBufferChannel (Kotlin reflection is not available) -> class dev.drathar.poktor.model.move.MoveTarget (Kotlin reflection is not available)
with response from http://localhost/api/v2/move-target/specific-move:
status: 200 OK
response headers:
Content-Type: application/jsonI don't have the slightest clue on why the requests are targeting
localhost
.
The client configuration I'm using is
internal class DefaultApiClient(mockEngine: HttpClientEngine? = null) : ApiClient {
override val httpClient = httpClient(mockEngine!!) {
defaultRequest {
url {
protocol = URLProtocol.HTTPS
host = "<http://pokeapi.co|pokeapi.co>"
path("api/v2/")
}
}
install(HttpCache)
install(ContentNegotiation) {
json(Json {
prettyPrint = true
isLenient = true
ignoreUnknownKeys = true
})
}
}
}
where the httpClient
function is declared as
expect fun httpClient(mockEngine: HttpClientEngine? = null, config: HttpClientConfig<*>.() -> Unit = {}): HttpClient
and defined on JVM as
actual fun httpClient(mockEngine: HttpClientEngine?, config: HttpClientConfig<*>.() -> Unit) = mockEngine?.let(::HttpClient) ?: HttpClient(OkHttp) {
config(this)
engine {
config {
retryOnConnectionFailure(true)
connectTimeout(0, TimeUnit.SECONDS)
}
}
}
All my tests are currently in the commonTest
module.
Do you have any idea on what the problem might be @Aleksei Tirman [JB]?Aleksei Tirman [JB]
07/30/2023, 8:38 AMRichard Hajdu
07/30/2023, 8:58 AMinternal class BerriesApiClient(mockEngine: HttpClientEngine? = null) : BerriesApi, ApiClient by DefaultApiClient(mockEngine) { ... }
and in a corresponding test I'd create the client as
private fun createClient(response: String): BerriesApiClient {
val mockEngine = MockEngine {
respond(
content = response, headers = headersOf(HttpHeaders.ContentType, "application/json")
)
}
return BerriesApiClient(mockEngine)
}
Richard Hajdu
08/02/2023, 6:30 AMAleksei Tirman [JB]
08/02/2023, 6:35 AMMoveTarget
but the body hasn't been transformed to that type (usually by the ContentNegotiation
plugin).Richard Hajdu
08/03/2023, 10:57 AMlocalhost
, isn't that sus? I mean, if the MockEngine
would be used it shouldn't be the case, right?Aleksei Tirman [JB]
08/03/2023, 11:31 AMMockEngine
because if you don't explicitly specify the host then the localhost
is assumed.Richard Hajdu
08/03/2023, 3:55 PMinternal class DefaultApiClient(engine: HttpClientEngine) : ApiClient {
override val httpClient = HttpClient(engine) {
defaultRequest {
url {
protocol = URLProtocol.HTTPS
host = "<http://pokeapi.co|pokeapi.co>"
path("api/v2/")
}
}
install(HttpCache)
install(ContentNegotiation) {
json(Json {
prettyPrint = true
isLenient = true
ignoreUnknownKeys = true
})
}
}
}
and don't modify the unit tests, everything works fine, but as soon as I replace the HttpClient
with the platform-specific one (which AFAIK inherits the ContentNegotiation
plugin from the shared config defined above) it just falls apart.
I'll have time to dig deeper into this tomorrow, I'll try to identify the root cause.Richard Hajdu
08/04/2023, 9:40 AMContentNegotiation
plugin, because I didn't config the HttpClient
properly with the optional MockEngine
.
The code before
actual fun httpClient(mockEngine: HttpClientEngine?, config: HttpClientConfig<*>.() -> Unit) = mockEngine?.let(::HttpClient) ?: HttpClient(OkHttp) {
config(this)
...
}
and after
actual fun httpClient(mockEngine: HttpClientEngine?, config: HttpClientConfig<*>.() -> Unit) = mockEngine?.let { HttpClient(it) { config(this) } } ?: HttpClient(OkHttp) {
config(this)
...
}
See how I simply created the HttpClient
using the default constructor without configuring the engine properly before.