如何在使用 Retrofit 2 进行单元测试期间创建 retrofit.Response 对象

新手上路,请多包涵

在使用 RxJava 和 Retrofit 2 时,我正在尝试创建单元测试以涵盖我的应用何时收到特定响应。

我遇到的问题是,在 Retrofit 2 中,我看不到一种不使用反射来创建 retrofit.Response 对象的好方法。

 @Test
public void testLogin_throwsLoginBadRequestExceptionWhen403Error() {

    Request.Builder requestBuilder = new Request.Builder();
    requestBuilder.get();
    requestBuilder.url("http://localhost");

    Response.Builder responseBuilder = new Response.Builder();
    responseBuilder.code(403);
    responseBuilder.protocol(Protocol.HTTP_1_1);
    responseBuilder.body(ResponseBody.create(MediaType.parse("application/json"), "{\"key\":[\"somestuff\"]}"));
    responseBuilder.request(requestBuilder.build());

    retrofit.Response<LoginResponse> aResponse = null;

    try {
        Constructor<retrofit.Response> constructor= (Constructor<retrofit.Response>) retrofit.Response.class.getDeclaredConstructors()[0];
        constructor.setAccessible(true);
        aResponse = constructor.newInstance(responseBuilder.build(), null, null);
    } catch (Exception ex) {
        //reflection error
    }

    doReturn(Observable.just(aResponse)).when(mockLoginAPI).login(anyObject());

    TestSubscriber testSubscriber = new TestSubscriber();
    loginAPIService.login(loginRequest).subscribe(testSubscriber);

    Throwable resultError = (Throwable) testSubscriber.getOnErrorEvents().get(0);
    assertTrue(resultError instanceof LoginBadRequestException);
}

我尝试使用以下内容,但这会创建 OkHttp 响应与改造响应。

     Request.Builder requestBuilder = new Request.Builder();
    requestBuilder.get();
    requestBuilder.url("http://localhost");

    Response.Builder responseBuilder = new Response.Builder();
    responseBuilder.code(403);
    responseBuilder.protocol(Protocol.HTTP_1_1);

原文由 Graham Smith 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 307
2 个回答

retrofit.Response 类有静态工厂方法来创建实例:

 public static <T> Response<T> success(T body) {
  /* ... */
}

public static <T> Response<T> success(T body, com.squareup.okhttp.Response rawResponse) {
  /* ... */
}

public static <T> Response<T> error(int code, ResponseBody body) {
  /* ... */
}

public static <T> Response<T> error(ResponseBody body, com.squareup.okhttp.Response rawResponse) {
  /* ... */
}

例如:

 Account account = ...;
retrofit.Response<Account> aResponse = retrofit.Response.success(account);

要么:

 retrofit.Response<Account> aResponse = retrofit.Response.error(
  403,
  ResponseBody.create(
    MediaType.parse("application/json"),
    "{\"key\":[\"somestuff\"]}"
  )
);

注意:在最新的 Kotlin Retrofit 版本(2.7.1)中,建议使用这样的扩展方法:

 Response.error(
  400,
  "{\"key\":[\"somestuff\"]}"
    .toResponseBody("application/json".toMediaTypeOrNull())
)

这属于 Effective Java Item 1: Consider static factory methods instead of constructors

原文由 nhaarman 发布,翻译遵循 CC BY-SA 4.0 许可协议

使用 Response.Builder 的 Kotlin + Mockito + okhttp3 示例

val mockResponse: Response<MyResponseReturnType> =
            Response.success(mock<MyResponseReturnType>(),
                    okhttp3.Response.Builder()
                            .code(200)
                            .message("Response.success()")
                            .protocol(Protocol.HTTP_1_1)
                            .request(Request.Builder().url("http://test-url/").build())
                            .receivedResponseAtMillis(1619053449513)
                            .sentRequestAtMillis(1619053443814)
                            .build())

原文由 dianakarenms 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题