使用 Retrofit 和 MockWebServer 模拟无网络

Posted

技术标签:

【中文标题】使用 Retrofit 和 MockWebServer 模拟无网络【英文标题】:Simulate no network using Retrofit and MockWebServer 【发布时间】:2014-09-17 02:50:24 【问题描述】:

我想模拟使用RetroFitMockWebServer时的无网络情况。

我目前正在使用Espresso 进行测试,并在开始测试之前将MockWebServers url 提供给RestAdapter。这对于模拟服务器响应等非常有用,但我看不到一种简单的方法来编写当设备没有网络时抛出的java.net.ConnectException 异常。我可以看到 MockResponse 允许限制模拟等,但不是自定义异常。

我知道我可以从根本上模拟 retrofit 使用的实际 Web api 接口,但如果可能的话,我想使用与其他测试相同的方法,使用 MockWebServer

我想我只是错过了一些简单的事情:)

谢谢

【问题讨论】:

【参考方案1】:

Retrofit 有一个 retrofit-mock 模块,它提供了一个 MockRestAdapter 类,其目的是模拟网络延迟和错误。

这是一个与普通RestAdapter 一起使用来创建服务实例的方法。您可以在 repo 的 samples/mock-github-client/ 文件夹中看到完整示例:https://github.com/square/retrofit/tree/parent-1.9.0/retrofit-samples/mock-github-client

MockRestAdapter 提供这些 API:

setDelay - 设置网络往返延迟,以毫秒为单位。 setVariancePercentage - 设置网络往返延迟的正负方差百分比。 setErrorPercentage - 设置对calculateIsFailure() 的调用百分比,返回true

在您的测试中,您可以致电setErrorPercentage(100) 以保证会发生网络错误。默认情况下,抛出错误的时间是延迟的 0 到 3 倍。将延迟设置为 0 以获得即时结果。

【讨论】:

链接坏了:( 更新链接:github.com/square/retrofit/blob/master/retrofit-mock/src/test/… 先生,我尝试将改造的 baseurl 覆盖为来自 mockwebserver 的那个,但是在执行测试时我仍然最终会调用 webservice,有没有办法阻止它?请协助。 @tony19,杰克·沃顿【参考方案2】:

使用 MockWebServer 模拟网络问题的最简单方法是将 SocketPolicy 设置为 SocketPolicy.DISCONNECT_AT_START、SocketPolicy.NO_RESPONSE 等:

MockWebServer server = new MockWebServer();

MockResponse response = new MockResponse()
  .setSocketPolicy(SocketPolicy.DISCONNECT_AT_START);

server.enqueue(response);

通过这种方式,您可以模拟网络错误,例如连接在响应之前过早关闭或超时异常

【讨论】:

【参考方案3】:

要清楚这里的异常类型,您可以看到不同之处:

Internet Connection Error

所以你可以得到两种类型:

UnknownHostException - 当您没有互联网或未知主机时...为了模拟这种情况,请为适配器设置一个不正确的端点。

ConnectException - mockwebserver 可以抛出超时异常。您可以在此处查看操作方法:

https://github.com/square/okhttp/tree/master/mockwebserver

我真的不知道你的代码是怎样的,但我希望这很有用

【讨论】:

+1 感谢您的回答,但它并没有真正回答问题,因为我想模拟没有网络而不是超时。调度员很有趣。我想知道我是否可以抛出上述异常...... 似乎我无法检查网络异常,并且调度程序仅根据其接口抛出 Inturrupted【参考方案4】:

不知道有没有用,不过可以用 MockWebServer 模拟超时:

String contentType = "Content-type: application/json";
MockResponse response = MockResponse().setResponseCode(statusCode).setBody(responseBody).addHeader(contentType);
MockWebServer proxy = new MockWebServer();
proxy.enqueue(response);
proxy.setBodyDelayTimeMs(timeoutDelay));
proxy.play(10000); //Number port - Important!!!

注意:请将您的代码(例如 AsyncHttpClient)的 HttpClient 设置为该端口以进行测试。

【讨论】:

【参考方案5】:

对我有用的是将改造 URL(端点)指向一个随机的不存在的主机。 我使用“thisIsARandomHost.com”和宾果游戏,我能够模拟未知主机异常。

例如:setAPP_URL = "http://thisIsARandomHost.com/";

在这里,setAPP_URL 是包含我传递给改造的 url 的字符串变量,当我想在测试中模拟未知主机异常时,我将 url 设置为如上。对于所有其他目的,它被设置为有效的 URL我的应用需要。

如上述答案所述,MockWebServer 是一个用于模拟改造响应的出色库,但您不需要该库来模拟此异常。对于模拟所有其他异常,我会推荐 MockWebServer ,我在我的项目中经常使用它来测试响应。

注意:您可以将应用网址设置为任何内容,只要该网址在网络上不存在即可。

【讨论】:

【参考方案6】:

mockWebServer.shutdown() 在执行单元测试之前没问题。

它在内部关闭套接字连接:

serverSocket!!.close()

【讨论】:

以上是关于使用 Retrofit 和 MockWebServer 模拟无网络的主要内容,如果未能解决你的问题,请参考以下文章

Retrofit 使用简介

Android 网络框架 Retrofit2.0介绍使用和封装

使用 Retrofit 和 MockWebServer 模拟无网络

MVP+Retrofit+RxJava+Dagger框架

MVP+Retrofit+RxJava+Dagger框架

Retrofit2.0使用详解