Robolectric + OkHttp + Retrofit + RxJava单元测试

7
我正在尝试使用Robolectric编写一段代码的单元测试,但问题在于我需要伪造http调用,而Robolectric的伪造层似乎只能与Apache的HttpClient一起使用,正如这个答案所述:链接。在Retrofit中,您无法更改URL,因此MockWebServer似乎不是一个选项。看起来mockito可以捕获retrofit回调,但我正在使用rxJava,所以我不知道它是否有帮助。是否有人对使用Robolectric + Retrofit + okHttp + rxJava进行单元测试有任何建议?下面是一小段示例代码:
    @Test
public void test1() throws IOException, InterruptedException {
    FragmentA frag = (FragmentA) activity
            .getFragmentManager().findFragmentById(
                    R.id.frag);
    assertThat(frag).isNotNull();
    assertThat(frag.isVisible()).isTrue();

    EditText input1 = (EditText) frag.getView()
            .findViewById(R.id.edit_text1);
    EditText input2 = (EditText) frag.getView()
            .findViewById(R.id.edit_text2);
    Button button = (button) frag.getView()
            .findViewById(R.id.button);
    input1.setText("999");
    input2.setText("999");
    Robolectric.addPendingHttpResponse(200, "{\"isValid\": true}");
    button.performClick();
            assertThat(
            ShadowAlertDialog.getLatestDialog() instanceof ProgressDialog)
            .isTrue();

  }

Robolectric.addPendingHttpResponse无论如何也行不通,因为OkHttp的缘故。API调用是在按下按钮时启动的,所以我需要在那个时刻伪造响应!
2个回答

1
你可以从build.gradle中声明的常量中获取服务器URL,并添加一个测试flavor或buildType来覆盖它。
release {
    buildConfigField "String", "SERVER_URL", "\"github.com\""
}
testing {
    buildConfigField "String", "SERVER_URL", "\"127.0.0.1\""
}

另一种不仅适用于Android的替代方案(在我看来不太优雅,但在所有情况下都有效)是使用一个仅在测试期间可访问和使用的私有变量,像这样使用反射:
  1. 创建一个私有静态变量,即private static String BASE_URL = null;
  2. 使用一个方法获取主机URL,在该方法中检查是否使用BASE_URL(永远不会在发布版本中使用),或者从资源中获取URL(永远不要在代码中硬编码URL)
  3. 在测试期间,使用反射将私有可见性更改为公共,并将BASE_URL修改为您的测试URL。
要执行反射部分,请使用此示例:
final Field urlField = MyService.class.getDeclaredField("BASE_URL");
urlField.setAccessible(true);
urlField.set(null, TEST_URL );

0
为什么不能在Retrofit中更改URL?
RestAdapter restAdapter = new RestAdapter.Builder()
    .setEndpoint("https://api.github.com")
    .build();

你可以从MockWebServer中设置该URL:

MockWebServer server = new MockWebServer();
URL url = server.getUrl("/");

我无法这样做,因为RestAdapter是应用程序类的扩展部分。因此,在setUp方法中,我只是生成活动,也生成应用程序,应用程序类包含默认api服务url的RestAdapter。我可以在应用程序类中添加一个公共方法,让我在后面更改RestAdapter,但这意味着仅为测试目的添加代码,这是错误的! - fedestylah
是的,这是错误的。我们一直面临同样的问题,即创建模拟对象。经过大量阅读后,创建模拟对象的解决方案是创建工厂来注入依赖项。因此,您将更改代码以创建工厂,而不是为了测试目的(如果您希望这样看的话 :P)。 - mromer
但无论如何,你正在做一些你本不需要做的工作! :) 如果我找不到更好的方法,我会尝试你的方式。你有任何链接或示例可以解释工厂模式吗?因为我对工厂模式不是很自信。谢谢! - fedestylah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接