Prerequisites: OkHttp 3.x/4.x, Wiremock 2.x, Robolectric 4.9.x
// build.gradle.kts
dependencies {
testImplementation("org.robolectric:robolectric:4.9.2"
testImplementation("com.github.tomakehurst:wiremock-jre8-standalone:2.35.0")
testImplementation("com.squareup.okhttp3:okhttp-tls:4.10.0")
}
Now for the actual test it’s important that your System Under Test (SUT) is able to configure it’s OkHttpClient
instance:
class SomeHttpClient @VisibleForTesting internal constructor(client: OkHttpClient) {
constructor() : this(OkHttpClient())
fun execute(request: Request): Response =
client.newCall(request).execute()
}
…so that in your test you can configure the needed SSL building blocks:
...
val handshakeCertificates = HandshakeCertificates.Builder()
.addInsecureHost("localhost")
.build()
val hostnameVerifier = HostnameVerifier { hostname, _ -> hostname == "localhost" }
val sut = SomeHttpClient(
OkHttpClient.Builder()
.sslSocketFactory(handshakeCertificates.sslSocketFactory(), handshakeCertificates.trustManager)
.hostnameVerifier(hostnameVerifier)
.build()
)
...
For the Robolectric setup, you need to ensure that you disable Robolectric’s conscrypt implementation, because this does not work well with Wiremock:
@RunWith(RobolectricTestRunner::class)
@ConscryptMode(ConscryptMode.Mode.OFF)
class SomeHttpClientTest {
@get:Rule
val wiremockRule = WireMockRule(wireMockConfig().dynamicHttpsPort())
// val sut = ... (see above)
@Test
fun shouldRequestSomething() {
stubFor(
get(urlPathMatching("/echo$"))
.willReturn(aResponse().withBody("Hello World!"))
)
)
val response = sut.execute(
Request.Builder()
.url("${wiremockRule.baseUrl()}/echo")
.get()
.build()
)
// verify response
}
}