Home > Mobile >  Mock API calls with Retrofit coroutines Mockk
Mock API calls with Retrofit coroutines Mockk

Time:02-18

Later Edit

I ended up to have my api service methods suspended and refactor my code as suggested by @LordRaydenMK.

The reason for using the library ru.gildor.coroutines:kotlin-coroutines-retrofit it the first place was out of pure convenience AND it was before retrofit released the version which would support for coroutines.


Original Question

I have been trying for a couple of days to mock the API calls with no success. I'm using the following libraries:

  • retrofit - i think we are all familiar with it
  • ru.gildor.coroutines:kotlin-coroutines-retrofit - for a couple of useful coroutine extensions
  • io.mockk:mockk - for mocking

It is a simple case of mocking the API response

interface ApiService {

  @GET
  fun getMyData(@Header("x-value") myValue: String): Call<String>
}
class Usecase(api: ApiService) {

  suspend fun execute() {
    val result = api.getMyData(value: String).awaitResult()
    // do smth with that result for now just return it
   return (result as Result.Ok).value
  }
}
class UseCaseTest {
   private val api = mockk<ApiService>()

  @Test
  fun testApiCall() {
    coEvery { api.getMyData(any()) } returns CallTest.buildSuccess("you did it!")

    val result = useCase.execute()
    assertEquals(result, "you did it!")
  }
}

In the example above the test hangs on the awaitResult extension method.

What i have tried so far with no luck:

  • mockkStatic(ru.gildor.coroutines.retrofit.CallAwait) but with no success
  • mockk Call<String> and do a coEvery { mockedCall.awaitResult() } returns ....

I'm sure it's something simple that I'm missing and a pair of fresh eyes will spot it from a mile away.

CodePudding user response:

First thing:

getMyData is NOT a suspend function so probably you should NOT be using coEvery when mocking it (tho I'm not a Mockk user).

That being said, Retrofit does support suspend functions natively, so you could do:

interface ApiService {

  @GET
  suspend fun getMyData(@Header("x-value") myValue: String): String
}

that means no need for awaitResult in your use case. In this scenario you do need coEvery when mocking it.

  • Related