使用Robolectric模拟HttpResponse

12

我想使用 Robolectric 2.3-SNAPSHOT 测试一个将在后台执行请求的对象。为了隔离它,我试图模拟返回的 HttpResponse,但是经过几个小时的尝试仍然没有成功。

我创建了一个项目,任何人都可以克隆它。只需运行./gradlew check https://github.com/Maragues/RobolectricDummyProject (git clone https://github.com/Maragues/RobolectricDummyProject.git

我尝试了:

但测试失败,因为它们查询了真实的 URL。

  private static final String MOCKED_WORD = "MOCKED";

  @Test
  public void mockedRequestUsingMockServer() throws Exception {
    mMockWebServer.enqueue(new MockResponse().setBody(MOCKED_WORD));
    mMockWebServer.play();

    Robolectric.getFakeHttpLayer().interceptHttpRequests(false);
    Robolectric.getFakeHttpLayer().interceptResponseContent(false);

    String result = request.loadDataFromNetwork();

    assertEquals(MOCKED_WORD, result);
  }

  @Test
  public void mockedRequestUsingRobolectric() throws Exception {
    Robolectric.setDefaultHttpResponse(200, MOCKED_WORD);

    String result = request.loadDataFromNetwork();

    assertEquals(MOCKED_WORD, result);
  }

执行请求的代码

public String loadDataFromNetwork() throws Exception {
    // With Uri.Builder class we can build our url is a safe manner
    Uri.Builder uriBuilder = Uri.parse("http://robospice-sample.appspot.com/reverse").buildUpon();
    uriBuilder.appendQueryParameter("word", word);

    String url = uriBuilder.build().toString();

    HttpURLConnection urlConnection = (HttpURLConnection) new URL(url)
      .openConnection();
    String result = IOUtils.toString(urlConnection.getInputStream());
    urlConnection.disconnect();

    return result;
  }
可能相关的问题:
3个回答

5
你正在禁用 Roboelectric 的 HTTP 层,所以你正在使用真正的 HTTP 层。这意味着在你的测试中没有什么聪明的魔法发生:当你发送一个 HTTP 请求时,它真的会出去到互联网上(正如你所看到的)。
MockWebServer 并不能阻止这种情况。它只是在本地设置了一个 web 服务器,你的测试可以连接到它。
因此,要解决这个问题,你需要停止尝试连接到一个真实的服务器,而是连接到模拟服务器。为了做到这一点,你需要将 URL 注入/设置到请求中。
@Test
  public void mockedRequestUsingMockServer() throws Exception {
    mMockWebServer = new MockWebServer();
    mMockWebServer.play();
    mMockWebServer.enqueue(new MockResponse().setResponseCode(200).setBody(MOCKED_WORD));

    request.myUrl = mMockWebServer.getUrl("/");

    String result = request.loadDataFromNetwork();

    assertEquals(MOCKED_WORD, result);
    mMockWebServer.shutdown();
  }

关于MockWebServer的使用,你指引了我正确的方向,我之前一直在使用错误。这里有一个正确使用的例子:http://codrspace.com/bsphere/unit-testing-android-http-connections/。不过,Robolectric的问题是不同性质的。谢谢! - Maragues
刚刚已经完成了。感谢您的关注。因为您的回答是唯一一个真正帮助模拟HTTP请求的,所以我会把奖励授予您。希望您不介意我的修改,但是您的指示并不正确。 - Maragues
当然,关键是要让答案对未来的读者有用。感谢您的更新。 - Paul Hicks

2
原文如下:

结果发现,Robolectric的FakeHttpLayer仅适用于Apache的HttpClient,在Froyo以上版本中高度不推荐使用。摘自Robolectric的Google Group

话虽如此,使用HttpUrlConnection会给你带来麻烦。我建议尽可能使用Android的HttpClient实现,因为Robolectric会拦截所有对该库的调用,并让你设置 canned responses 来响应 HTTP 调用。我们正在考虑为HttpUrlConnection做同样的事情,但目前还不清楚何时会发生。

除此之外,单元测试不应该需要模拟HTTP层。我的方法从一开始就是错误的。

翻译如下:

结果发现,Robolectric的FakeHttpLayer只能与Apache的HttpClient一起使用,而在Froyo以上版本中强烈不推荐使用。这段文字摘自Robolectric的Google Group。

话虽如此,使用HttpUrlConnection会导致问题。建议尽可能使用Android的HttpClient实现,因为Robolectric可以拦截所有对该库的调用,并让您设置 canned responses 来响应HTTP调用。我们正在考虑为HttpUrlConnection做同样的事情,但目前还不清楚何时会发生。

除此之外,单元测试不应该需要模拟HTTP层。我的方法从一开始就是错误的。


2
为什么单元测试不应该模拟http层,它是一个外部依赖项,可能会引入一些未知和不稳定的结果,那么你如何确保特定的结果? - joecks
我也想知道为什么不应该模拟HTTP层。你能解释一下吗?正确的方法是什么? - ventura8

1
你可以尝试这个(参考:https://github.com/square/okhttp/tree/master/mockwebserver)。
  // Create a MockWebServer. These are lean enough that you can create a new
    // instance for every unit test.
    MockWebServer server = new MockWebServer();
    // Schedule some responses.
    server.enqueue(new MockResponse().setBody("it's all cool"));
    // Start the server.
    server.play();
    // Ask the server for its URL. You'll need this to make HTTP requests.
    //Http is my own http executor.
    Http.Response response = http.get(server.getUrl("/"));

然后,您可以将响应与server.enqueue(new MockResponse()。setBody(“it's all cool”));进行比较。
MockWebServer是okhttp https://github.com/square/okhttp/tree/master/mockwebserver的一部分。Android 4.4中的URLConnectionImpl已经从defaultHttpClient更改为Okhttp

我需要在Gradle中添加什么依赖才能使用MockResponse - IgorGanapolsky

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