mocking Retrofit response calls with Call not working

Jim Clermonts picture Jim Clermonts · Apr 16, 2018 · Viewed 14k times · Source

I'm mocking the response of the APIService. Unfortunately it is not working, I have to send back a Call but I don't understand how. The question is how to send back a Call object.

@RunWith(AndroidJUnit4::class)
class ApiServiceTest {

    @Test
    fun testSomething() {
        val apiService = ApiServiceMock()
        val call = apiService.getStep1User()
        val result = call.execute()
        Assert.assertEquals("SomeUserValue", result.body()!!.getResponse())
    }
}

Here is the mocked service:

class ApiServiceMock : ApiService {
    override fun getStep1User(): Call<UserResponse> {
        // How to return an object of type Call<UserResponse> ?
        val response = "{ \"Response\": \"SomeUserValue\" }"
        val gson = Gson().toJson(response)
        return Response.success(gson)
    }
}

Here is the api interface:

interface ApiService {

    @GET("/booky/step1user")
    fun getStep1User(): Call<UserResponse>

    companion object {

        val interceptor = HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
        val client = OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .build()

        val retrofit = Retrofit.Builder()
                .baseUrl("http://jimclermonts.nl")
                .addConverterFactory(MoshiConverterFactory.create().asLenient())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(client)
                .build()
    }
}

build.gradle:

implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.3.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'
implementation 'com.squareup.okhttp3:okhttp:3.9.0'
implementation "com.squareup.retrofit2:adapter-rxjava2:2.3.0"

implementation 'com.google.code.gson:gson:2.8.0'

testImplementation "org.mockito:mockito-core:2.12.0"
testImplementation "com.nhaarman:mockito-kotlin:1.5.0"
implementation 'org.mockito:mockito-android:2.18.0'

Answer

TpoM6oH picture TpoM6oH · Apr 18, 2018

Call is an interface, you can create an object that implements it and return it from your mocking method:

class ApiServiceMock : ApiService {
    override fun getStep1User(): Call<UserResponse> {
        return object: Call<SignedUserUi> {
            override fun enqueue(callback: Callback<UserResponse>?) {
            }

            override fun isExecuted(): Boolean {
                return false
            }

            override fun clone(): Call<UserResponse> {
                return this
            }

            override fun isCanceled(): Boolean {
                return false
            }

            override fun cancel() {

            }

            override fun request(): Request {
                return Request.Builder().build()
            }

            override fun execute(): Response<UserResponse> {
                // Create your mock data in here
                val response = "{ \"Response\": \"SomeUserValue\" }"
                val gson = Gson().toJson(response)
                return Response.success(UserResponse(gson))
            }

        }
    }
}

If you want to have less boilerplate and be able to mock interfaces in a single line I would recommend you to take a look at mockito for kotlin.

After including it to your project you'll be able to do

val rawResponse = "{ \"Response\": \"SomeUserValue\" }"
val gson = Gson().toJson(rawResponse)
val response = Response.success(UserResponse(gson))

val mockCall = mock<Call<UserResponse>> {
    on { execute() } doReturn response
}

val mockApiService = mock<ApiService> {
    on { getStep1User() } doReturn mockCall
}