使用Call无效的模拟Retrofit响应调用

时间:2018-04-16 09:36:02

标签: android retrofit2 okhttp3

我嘲笑APIService的回应。不幸的是它不起作用,我必须发回一个电话,但我不明白如何。问题是如何发送回Call对象。

@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())
    }
}

这是模拟服务:

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)
    }
}

这是api界面:

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'

4 个答案:

答案 0 :(得分:6)

调用是一个接口,您可以创建一个实现它的对象并从模拟方法返回它:

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))
            }

        }
    }
}

如果你想减少样板并且能够在一行中模拟界面,我建议你看一下mockito的kotlin。

将它包含到您的项目后,您将能够

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
}

答案 1 :(得分:5)

您要做的是testin改造! 您必须在获得响应后断言您的应用程序的行为,而不是断言什么改进得到请求的响应! 例如断言错误响应,必须出现错误对话框。

您可以使用OkHTTPMock服务器模拟响应。 在build.gradle模块文件中添加依赖项:

testImplementation 'com.squareup.okhttp3:mockwebserver:lastVersion'

然后在您的测试文件中,您可以模拟服务器,请求和响应。 这里有一个例子:

MockWebServer server = new MockWebServer();
server.enqueue(new MockResponse().setBody("{ \"Response\": \"SomeUserValue\" }"));
// Start the server.
  server.start();

//and than load your request. Be Careful, they are executed in the order that you enqued them!

//Add your assertion (Succes response and error response)
//if you are working with MVP architecture, you can assert for the success case
//that method showData(data) is called using Mockito.
verify(myPresenter).showData(data);

看看OkHttpMock

的行李example

答案 2 :(得分:1)

您可以使用RETURNS_DEEP_STUBS。但不确定在Kotlin中如何工作。

mock = Mockito.mock(Api.class, RETURNS_DEEP_STUBS)
when(mock.getSomething().execute()).thenReturn(Response.success(...));

答案 3 :(得分:0)

您需要使用辅助类来模拟响应。

class CallFake<T>(
    private val response: Response<T>) 
: Call<T> {

companion object {
    inline fun <reified T> buildSuccess(body: T): CallFake<T> {
        return CallFake(Response.success(body))
    }

    inline fun <reified T> buildHttpError(errorCode: Int, contentType: String, content: String): CallFake<T> {
        return CallFake(Response.error(errorCode, ResponseBody.create(MediaType.parse(contentType), content)))
    }
}

override fun execute(): Response<T> = response

override fun enqueue(callback: Callback<T>?) {}

override fun isExecuted(): Boolean = false

override fun clone(): Call<T> = this

override fun isCanceled(): Boolean = false

override fun cancel() {}

override fun request(): Request? = null 
}

然后在你的测试类中,你必须使用下面所示的函数来说明调用apiService时要返回的内容。

@RunWith(MockitoJUnitRunner::class)
class ApiServiceTest {
@Mock
lateinit var apiService: ApiService

@Test
fun testSomething() {
    Mockito.`when`(apiService.getStep1User())
            .thenReturn(CallFake.buildSuccess(UserResponse("SomeUserValue")))

    val call = apiService.getStep1User()
    val response = call.execute()
    val userResponse = response.body() as UserResponse

    Assert.assertEquals("SomeUserValue", userResponse.userValue)
}
}