web-dev-qa-db-ja.com

コールが機能しないとレトロフィット応答コールをモックする

APIServiceの応答をモックしています。残念ながら機能していません。Callを返送する必要がありますが、その方法がわかりません。問題は、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'
12
Jim Clermonts

呼び出しはインターフェイスであり、それを実装するオブジェクトを作成して、モックメソッドから返すことができます。

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

        }
    }
}

定型文を減らして、インターフェースを1行でモックできるようにする場合は、kotlinの mockito を確認することをお勧めします。

プロジェクトに含めると、次のことができるようになります。

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
}
8
TpoM6oH

あなたがやろうとしているのは、改造をテストすることです!応答を取得した後、アプリケーションの動作をアサートする必要があります。要求の応答として取得するレトロフィットをアサートする必要はありません。たとえば、エラー応答をアサートすると、エラーダイアログが表示されます。

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

Officielを見てください OkHttpMock

5
Fakher

RETURNS_DEEP_STUBSを使用できます。しかし、Kotlinでどのように機能するかはわかりません。

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

ヘルパークラスを使用して応答をモックする必要があります。

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 
}

次に、テストクラスで、次に示すようにwhen関数を使用して、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)
}
}
1
Daniel RL