user3745870
user3745870

Reputation: 321

How to mock a POST request with mockk and fuel in kotlin?

I am making some http requests in kotlin with fuel library. I want to test that code using mockk library. I figured out how to mock http requests. Below is the code for that.

    val client = mockk<Client>()
    every { client.executeRequest(any()).statusCode } returns 200
    every { client.executeRequest(any()).responseMessage } returns "test"
    every { client.executeRequest(any()).data } returns "abc".toByteArray()

    FuelManager.instance.client = client

    assertEquals("abc" , testHttpRequest())

I do not like that any() here. I want to be specific about the http method and the url. I would like to return specific responses based on the url being called and the http method being used.

I figured may be I could do following

    val req = Request(Method.POST, "my/test", URL("https://testRequest.com"), timeoutInMillisecond = 3000, timeoutReadInMillisecond = 3000)

    every { client.executeRequest(req).statusCode } returns 200
    every { client.executeRequest(req).responseMessage } returns "OK"
    every { client.executeRequest(req).data } returns "abc".toByteArray()

    FuelManager.instance.client = client

But I am getting following error.

io.mockk.MockKException: no answer found for: Client(#1).executeRequest(--> 
https://testRequest.com/my/test
"Body : abc"
"Headers : (3)"
Accept-Encoding : compress;q=0.5, gzip;q=1.0
Content-Type : application/json
Authorization : Basic xxx)

What am I missing here?

Upvotes: 7

Views: 5869

Answers (3)

Rich
Rich

Reputation: 11

To all those people that ended up here trying to find a solution to this, I've found something that solves the problem for my use case (but there are likely many use cases it's not appropriate for and I accept that it may not be the nicest...).

Provided you always have the calls to different endpoints in the same order every time you can do -

every { client.executeRequest(any()).data} returnsMany listOf(responseBody1, responseBody2, ... , responseBodyN)

Which will return the next response body for every subsequent call to the Fuel client.

The full code would look like (using OP's example) -

val response1 = "This is response one"
val response2 = "This is response two"

val client = mockk<Client>()
    every { client.executeRequest(any()).statusCode } returns 200
    every { client.executeRequest(any()).responseMessage } returns "test"
    every { client.executeRequest(any()).data } returnsMany listOf(response1.toByteArray(), response2.toByteArray())

    FuelManager.instance.client = client

    assertEquals("This is response one", testHttpRequest())
    assertEquals("This is response two", testHttpRequest())

I suspect the correct way to do this is with a 'CustomMatcher' extension function on the MockKMatcherScope as detailed here. I could only get the mock to response with the last item that'd been mocked when doing that, rather than the correct item but YMMV...

Upvotes: 1

nanangarsyad
nanangarsyad

Reputation: 700

You could try these lines. Regarding how to intercept fuel request.

fun interceptFuel(method: Method, url: String) {
    val interceptor = { next: (Request) -> Request ->
        { req: Request ->
            if (req.method == method && req.url.toString() == url) {
                val client = mockk<Client>()
                /*mock fuel into whatever you like*/
                FuelManager.instance.client = client
            }
            next(req)
        }
    }
    FuelManager.instance.addRequestInterceptor(interceptor)
}

then, use it like this

interceptFuel(Method.GET, "https://google.com") 

BTW, this code not fully tested. Use at your own risk

Upvotes: 0

Vova
Vova

Reputation: 1091

Try to use following:

 every { client.executeRequest(req) } returns <mock object>

Upvotes: 0

Related Questions