hey channel. this is my first unit test using kotl...
# spring
a
hey channel. this is my first unit test using kotlin with Spring, MockK and I am getting this error with dependency injection
Could not inject field: private final <http://java.net|java.net>.http.HttpClient com.attune.ingestion.kafka.consumer.api.service.IngestionConsumerServiceTest.httpClient; nested exception is java.lang.IllegalStateException: The existing value '<http://jdk.internal.net|jdk.internal.net>.http.HttpClientImpl@668ea404(1)' of field 'private final <http://java.net|java.net>.http.HttpClient com.attune.ingestion.kafka.consumer.api.service.IngestionConsumerServiceTest.httpClient' is not the same as the new value 'HttpClient(<http://java.net|java.net>.http.HttpClient#0 bean#1)'
I would like to mock HttpClient using this instead of use WireMock:
Copy code
@MockkBean val httpClient: HttpClient.Builder = HttpClient.newBuilder()
Please, any ideas to fix that and improves it, will be helpful.
s
Try using a
lateinit
property:
Copy code
@MockkBean lateinit var httpClient: HttpClient
d
You are using
@MockkBean
with a concrete implementation, which is silly
And your service wants a HttpClientConfig injected,not an actual HttpClient; you can use a TestConfiguration if you want to override bean with a concrete implementation
a
hi @Sam if I try with
Copy code
@MockkBean lateinit var httpClient: HttpClient
I get:
lateinit property httpClient has not been initialized
hi @Davio I didn’t follow you because I am passing the
httpClientConfig
to the constructor here:
Copy code
private val service: IngestionConsumerService = IngestionConsumerService(apiPathsConfig, httpClientConfig, 3L)
I also agree with you that I am using
@MockBean
with the concrete implementation but I please, what would you do in this case to avoid of concrete implementation?
k
On this line:
Copy code
private val httpClientConfig = HttpClientConfig().apply { httpClient }
Your
apply
function has no effect. You are just mentioning a variable
httpClient
whose value is ignored because you are not assigning it to anything.
d
Overall, it's kind of hard to give advice because different things are going wrong, both Kotlin specific and Spring specific. Maybe you should make it work in Spring first and only then try to translate it to Kotlin?
🙏 1
a
can you see this example?
it works mocking them
I mean… first of all I mocked only what I needed but like you said I now mixed the
@MockBean
and concrete implementation
hey @Davio I would like to share that works doing this:
Copy code
@ExtendWith(SpringExtension::class)
class IngestionConsumerServiceTest {

    @MockkBean
    lateinit var httpClient: HttpClient
    @MockkBean
    lateinit var httpResponse: HttpResponse<Any>


    @Test
    fun `Consuming from a valid protobuf topic message, sending to the ingestion service and waiting for Status CREATED`() {
        every { httpResponse.statusCode() } returns 200
        every { httpClient.send(any(), any<BodyHandler<Any>>()) } returns httpResponse

        val httpRequestTimeout = 3L
        val pathsMap = mapOf("__v2__uploads" to "<http://localhost:8085/>", "__api__v3__data" to "<http://localhost:8085/>")
        val apiPathsConfig = ApiPathsConfig().apply { paths = pathsMap }
        val service = IngestionConsumerService(apiPathsConfig, httpClient, httpRequestTimeout)

        val ingestionHttpRequest = IngestionHttpRequest.HttpRequest.newBuilder()
            .setMethod("post")
            .setPath("/api/v3/data")
            .setHttpVersion(HttpClient.Version.HTTP_1_1.toString())
            .setHttpBody("YXR0dW5laW90".toByteStringUtf8())
            .build()
        val ingestionHttpRequestConsumer = ConsumerRecord(
            "ingestion-topic", 1, 1, "ingestionKey", ingestionHttpRequest
        )
        service.consumeIngestion(ingestionHttpRequestConsumer)

        val request = slot<HttpRequest>()
        val requestHandler = slot<BodyHandler<Any>>()
        verify { httpClient.send(capture(request), capture(requestHandler)) }
        assertEquals(HttpMethod.POST.name, request.captured.method())        assertEquals(ingestionHttpRequest.httpBody.toByteArray(), listOf(request.captured.bodyPublisher().get()).get(0).boxedValue)
        assertEquals(apiPathsConfig.paths[ingestionHttpRequest.path], request.captured.uri())
        assertEquals(httpRequestTimeout, request.captured.timeout().get().seconds)
    }
}
k
what's the point of mocking response?
a
@User the Service does not provide the http response. This will be done in another ticket because of concerns related to Sync/Async commit
any idea or suggestion for that would be helpful
495 Views