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?
verify supports the same argument matchers as every , along with a few additional matchers. Inside the verification block (between the opening curly bracket { and closing curly bracket } ), you write the method you want to verify.
A relaxed mock is the mock that returns some simple value for all functions. This allows you to skip specifying behavior for each case, while still stubbing things you need.
Mocking static methods Again, MockK provides specialized functions to mock static methods. mockkStatic("com.name.app.Writer") Rather than passing a reference to the class, you pass the class name as a string. You can also choose to pass in a reference to the class, and MockK will figure out the class name.
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...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With