webentwicklung-frage-antwort-db.com.de

mocking Antwortanrufe nachrüsten, bei denen der Anruf nicht funktioniert

Ich verspotte die Antwort des APIService. Leider funktioniert es nicht, ich muss einen Anruf zurückschicken, aber ich verstehe nicht wie. Die Frage ist, wie ein Call-Objekt zurückgeschickt wird. 

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

Hier ist der verspottete Dienst:

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

Hier ist die API-Schnittstelle:

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'
11
Jim Clermonts

Was Sie zu tun versuchen, ist testin retrofit! Sie müssen das Verhalten Ihrer Anwendung nach Erhalt der Antwort bestätigen, nicht auf das Retrofit als Antwort auf die Anforderung !! Zum Beispiel, dass eine Fehlerantwort angegeben wird Es muss ein Fehlerdialogfeld angezeigt werden.

Sie können die Antwort mit dem OkHTTPMock-Server simulieren Fügen Sie die Abhängigkeit in Ihre build.gradle-Moduldatei ein:

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

und dann können Sie in Ihrer Testdatei einen Server, eine Anfrage und eine Antwort simulieren. Hier ein Beispiel:

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

Schauen Sie sich das offizielle Beispiel von OkHttpMock an

5
Fakher

Call ist eine Schnittstelle. Sie können ein Objekt erstellen, das es implementiert, und es von Ihrer Mocking-Methode zurückgeben:

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

        }
    }
}

Wenn Sie weniger Boilerplate haben und Schnittstellen in einer einzigen Zeile simulieren möchten, würde ich Ihnen empfehlen, einen Blick auf mockito für kotlin zu werfen.

Nachdem Sie es in Ihr Projekt aufgenommen haben, können Sie dies tun

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

Sie können RETURNS_DEEP_STUBS verwenden. Aber nicht sicher, wie es in Kotlin funktioniert.

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

Sie müssen eine Hilfsklasse verwenden, um Antworten zu simulieren.

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 
}

und dann in Ihrer Testklasse müssen Sie die Funktion wie unten gezeigt verwenden, um anzugeben, was beim Aufruf von apiService zurückgegeben werden soll.

@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)
}
}
0
Daniel RL