一年三次OkCupid开发商拿地把我们188bet金宝搏官网的日常职责到一边,享受“哈克周”,一个完整的工作周,让我们的追求,我们希望与更多的自由探索和学习来解决问题。

今年春天,我花了一周,终于潜水进一步融入咖啡的测试。我自动化的应用与前这个工具,但是有一个问题与咖啡的测试,我一直挣扎:网络嘲讽。

有大量的指南,包括官方咖啡文档这帮助您开始自动化您的应用程序,但如果你想编写可靠的UI测试你需要模拟你的网络层。如果不这样做,你的测试可能会不一致。让我们考虑OkCupid测试DoubleTake(这是你滑动用户卡左/右投188bet金宝搏官网票对他们的主屏幕)。如果没有嘲讽的网络,我不知道:

  • 哪个用户将首先出现在卡的堆叠。
  • 如果只有用户卡将出现(而不是广告或特殊的公告)。
  • 如果喜欢,用户将导致相互匹配,即使我的测试并不指望它。

对于OkCupi188bet金宝搏官网d应用,嘲笑网络层似乎是特别具有挑战性的任务。我们不使用匕首或其他依赖注入框架,现在,有很多我们的网络代码是紧耦合的应用程序类。事实证明,虽然,在所有这不是一个大问题!

什么工具应该怎么用?

当我刚开始这项工作,我试过WireMock。WireMock是一个HTTP嘲讽的工具,可以让你在Android设备上运行的HTTP服务器的权利,你的应用程序可以使用的,而不是说你自己的服务器进行通信。188博金宝电子体育频道我了解WireMock感谢萨姆·爱德华兹在纽约Droidcon 2017年,他去哪里了深入讲解WireMock如何可以用来模拟HTTP的API。如果你在WireMock深入指导找一个,我强烈建议。

然而,萨姆还提到另一个叫工具MockWebServer。MockWebServer是实现同一目标的一个广场库 - 为您的HTTP响应运行模拟服务。MockWebServer实际上是重量越来越轻,并尝试后我都找到了MockWebServer的设置要方便很多(添加WireMock作为gradle这个依赖给了我几次冲突,我不得不解析)。由于MockWebServer拥有所有我需要的能力,我决定与前进。

地基

在我们继续之前实现MockWebServer,让我们来谈谈一些我们可以做,以使这项工作的基础工作。MockWebServer将启动本地主机上的Web服务器,这意味着我们所有的请求都过不去HTTP://本地主机:8080代替HTTP:// myendpoint。交换的端点的测试应用程序可以通过两个步骤来完成:

  1. 创建扩展您的正常应用类TestApplication,并覆盖你的基本URL。
  2. 创建将使用您的测试应用程序自定义的JUnit运行。

创建TestApplication

首先,让我们考虑,我们有我们自己的应用程序类,它暴露了我们的API网址:

公开课OkApp:应用程序(){开开心getApiUrl():字符串{回报的 “http:// apiurl”}}

里面你AndroidTe188博金宝电子体育频道st目录,创建可扩展您在应用程序中使用了一个应用程序类:

类TestApplication:OkApp(){控乐趣getApiUrl():字符串{回报 “http://127.0.0.1:8080”}}

注意这里我只是重写返回,而不是一个应用程序使用本地主机API网址,一个方法。这是否意味着我们所有的应用程序的请求将达到本地主机?不完全是,咖啡依然采用我们的正常应用程序类。为了解决这个问题,我们需要一个可定制的运行。

自定义的JUnit运行

创建自定义的JUnit运行只需要一个快速更新:覆盖newApplication方法并将它指向您的测试应用程序类,而不是原来的:

类MockTestRunner:Android188博金宝电子体育频道JUnitRunner(){控乐趣的onCreate(参数:捆绑){StrictMode.setThreadPolicy(。StrictMode.ThreadPolicy.Builder()permitAll()构建())super.onCreate(参数)}覆盖乐趣newApplication(CL:ClassLoader的?类名:字符串?上下文:上下文):应用程序{回报super.newApplication(CL,TestApplication :: class.java.name,上下文)}}

然后,我们需要进入我们的应用程序的文件的build.gradle并配置它指向这个亚军,而不是:

188博金宝电子体育频道安卓{{defaultConfig testInstrumentationRunner 'com.my.package.MockTestRunner'}}

现在,我们有我们的基础设置,以及我们的应用程序指向本地主机,让我们的东西在那里运行。

MockWebServer设置

我们可以复制开始/粘贴包括MockWebServer依赖的步骤:

188博金宝电子体育频道androidTestImplementation “com.squareup.okhttp3:mockwebserver:$ {} version.okhttpVersion”

接下来,我们需要火了我们的模拟Web服务器为每个测试。我们可以配置的设置和我们的测试类内部拆卸方法:

@RunWith(188博金宝电子体育频道AndroidJUnit4 ::类)类MainActivityTest {// ...私人VAR mockWebServer = MockWebServer()@Before乐趣设置(){mockWebServer.start(8080)} @After乐趣拆解(){mockWebServer.shutdown()}// ...}

当我们开始我们的Web服务器,我们给它一个端口上运行。这是我们在我们的测试应用程序类有相同的端口;这一点很重要,这些对齐。如果你想在这里多一点安全,您可以将端口到一个构建配置领域。

回应嘲讽

在做这一步恭喜!我敢肯定,这是一个很大跟随。让我们看一下我们现在的情况:

  • 我们已经创建了一个TestApplication类,它使我们可以覆盖任何东西,我们一般的应用程序将使用。
  • 我们学会了如何实现自己的自定义的JUnit运行使用这个TestApplication类。
  • 我们做了它,这样,当我们的应用程序运行连接测试,它会说话,而不是为localhost走出去公司的服务器。

所有伟大的事情!不幸的是,我们没有任何嘲讽的回应呢。如果你运行你的测试,因为他们,你会看到很多404错误。所以,让我们来谈谈我们如何才能解决这个问题。

文件读取样板

从广义上讲,我们有两种方法在这里:让我们的嘲弄响应从模型编程对象,或JSON文件阅读我们的模拟响应(如果你有一个原因是优于其他的想法,叫我出来在Twitter上因为我真的不知道什么是最好的在这里)。我选择使用的文件,我就简单介绍一下加入到做到这一点的样板代码。

要将所有文件保存在以下位置:

应用程序/ src目录/调试/资产/ network_files / endpoint_success.json

我选择调用文件夹network_files,但你可以叫它任何你喜欢的。现在,我们有我们的JSON文件,我们需要一种方法来阅读。我创建了以下AssetReaderUtil.kt文件并将其存储在我的androidTest目录:188博金宝电子体育频道

对象AssetReaderUtil {乐趣资产(背景:背景下,assetPath:字符串):字符串{尝试{VAL的inputStream = context.assets.open( “network_files / $ assetPath”)返回inputStreamToString(的inputStream, “UTF-8”)}赶上(E:IOException异常){抛出的RuntimeException(E)}}私人乐趣inputStreamToString(的inputStream:InputStream中,的charsetName:字符串):字符串{VAL建设者=的StringBuilder()VAL读卡器= InputStreamReader的(的inputStream,的charsetName)reader.readLines(){的forEach建设者.append(它)}返回builder.toString()}}

现在我们已经有了这一点,让我们穿行使用这些嘲笑。

调度员

MockWebServer使用一种叫做调度员办理嘲笑服务器响应。它包括我们覆盖一个方法,它告诉我们的要求是什么,让我们回到一个模拟响应具体到这一点。

这里是我的调度员的工作原理:

  • 它接受一个背景下,这是用来从我们在上一步中创建的文件阅读。
  • 它包含一个端点映射到文件名的模拟响应映射属性。
  • 如果调度方法找到了请求端点一个文件名,它会返回嘲笑回应。
  • 如果没有发现假文件,我们将返回404。

这里是所有的代码:

类SuccessDispatcher(私人VAL上下文:上下文= InstrumentationRegistry.getInstrumentation()上下文。):调度(){私人VAL responseFilesByPath:地图<字符串,字符串> = mapOf(APIPaths.ENDPOINT_ONE到MockFiles.ONE_SUCCESS_FILE,APIPaths.ENDPOINT_TWO到MockFiles.TWO_SUCCESS_FILE)重写乐趣调度(请求:RecordedRequest):MockResponse {VAL错误响应= MockResponse()setResponseCode(404)VAL pathWithoutQueryParams = Uri.parse(请求。路径)。路径:?返回错误响应VAL responseFile = responseFilesByPath [pathWithoutQueryParams]返回如果(responseFile!= NULL){VAL responseBody =资产(背景下,responseFile)MockResponse()。setResponseCode(200).setBody(responseBody)}其他{错误响应}}}

我命名这个调度SuccessDispatcher因为它只返回成功响应。如果你想覆盖的回应,我建议从转向端点的静态地图客场文件名,而是暴露的方法,它允许您定义什么应该被嘲笑为每个端点。

莫克在开始测试前

你需要知道的,最后一点是,你需要确保你开始MockWebServer之前运行应用程序。这有可能是你的应用程序使得网络请求时,它初始化,所以如果你第一次启动该应用程序(也就是咖啡默认)的东西可能不按预期方式工作。你可以调整ActivityTestRule的设置方法内推出,就像这样:

@RunWith(188博金宝电子体育频道AndroidJUnit4 ::类)类MainActivityTest {@JvmField @rule VAR activityTestRule = ActivityTestRule(MainActivity :: class.java,真,假)私人VAR mockWebServer = MockWebServer()@Before乐趣设置(){mockWebServer.start(BuildConfig.PORT)mockWebServer.dispatcher = SuccessDispatcher()activityTestRule.launchActivity(空)} @After乐趣拆解(){mockWebServer.shutdown()} // ...}

样品

现在,我们已经完成了所有这一切,我们可以写一个自动化测试是这样,这是使用所有模拟数据为自己,而不是与实际用户互动:

DTAutomation

如果你想看到,在操作使用这些工具超级基本的应用程序,随意叉此示例项目

我希望这可以帮到你!如果你有写MockWebServer调度员的任何问题,或其他独特的方式,找到我推特

想和我一起在OkCupid?188bet金宝搏官网我们正在招聘!