一年的三次Okcupid开发人员将我们188bet金宝搏官网的日常责任置于一边,享受“黑客周”,整个工作周,让我们追求我们想要解决更多自由来探索和学习的问题。

今年春天,我花了一周才能进一步潜入浓缩咖啡测试。我之前已经用这个工具自动化了应用程序,但是浓缩咖啡测试有一个问题,即我一直在挣扎:网络嘲笑。

有很多指南,包括官方espresso文档这有助于您开始自动化应用程序,但如果您想编写可靠的UI测试,您需要模拟网络层。没有这样做,您的测试可能不一致。让我们考虑在OKCupid中测试Doubletake(这是您将用户卡留下的188bet金宝搏官网主屏幕左/右键投票)。没有嘲笑网络,我不知道:

  • 哪个用户将在卡堆栈中显示。
  • 如果只出现用户卡(而不是广告或特殊公告)。
  • 如果喜欢用户将导致相互匹配,即使我的测试不期望它。

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

我应该使用什么工具?

当我第一次开始这个努力时,我试过丝袜。丝袜是一个HTTP模拟工具,允许您在Android设备上运行HTTP服务器,您的应用程序可以与您的服务器进行通信。188博金宝电子体育频道感谢我了解了Wiremock2017年Droidcon NYC的Sam Edwards,他深入解释威丝可以用来模拟HTTP API的方式。如果您在Wiremock寻找深度指南,我强烈推荐。

但是,Sam也提到了另一个名为的工具Mockwebserver。Mockwebserver是一个方形库,实现了相同的目标 - 为HTTP响应运行模拟服务。Mockwebserver实际上更轻,在尝试后,我发现模型的安装程序更容易了(添加Wiremock作为Gradle依赖性,给了我几个不得不解析的冲突)。由于Mockwebserver拥有所需的所有功能,因此我决定向前移动。

奠基

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

  1. 创建一个延长正常应用程序类的测试应用程序,并覆盖基本URL。
  2. 创建一个使用您的测试应用程序的自定义JUnit runner。

创建测试

首先,让我们考虑我们拥有自己的应用程序类,揭露我们的API URL:

打开类Okapp:application(){open fun getapiurl():string {return“http:// apiurl”}}

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

class testapplication:okapp(){override fun getapiurl():string {return“http://127.0.0.1:8080”}}

在这里通知我刚刚覆盖了一个返回localhost api url的方法,而不是应用程序使用的方法。这是否意味着我们所有的应用程序的请求都会达到本地主机?不完全,浓缩咖啡仍在使用我们的正常应用类。要解决此问题,我们需要一个自定义跑步者。

定制JUNIT赛跑者

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

Class Mocktestrunner:an188博金宝电子体育频道droidjunitrunner(){override fun oncreate(参数:捆绑?){strictmode.setthreadpolicy(strictmode.threadpolicy.builder()。permitall()。build())super.oncreate(参数)}覆盖有趣的新应用(cl:classloader?,classname:字符串?,上下文:上下文?):应用程序{return super.newapplication(cl,testapplication :: class.java.name,context)}}

然后,我们需要进入我们的应用程序的build.gradle文件,并将其配置为指向此Runner:

188博金宝电子体育频道android {defaultconfig {testinstrumentationrunner'com.my.package.mocktestrunner'}}

现在我们有我们的基础设置,我们的应用程序指向localhost,让我们在那里运行的东西。

Mockwebserver设置

我们可以从包括模型/粘贴步骤开始,包括Mockwebserver依赖项:

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

接下来,我们需要为每个测试冒出模拟Web服务器。我们可以在我们的测试类中配置和拆除方法中的:

@runwith(188博金宝电子体育频道androidjunit4 :: class)class mainActivitytest {// ...私有var mockwebserver = mockwebserver()@before fun setup(){mockwebserver.start(8080)} @After fun teardown(){mockwebserver.shutdown()}// ......}

当我们启动Web服务器时,我们会给它一个要运行的端口。这是我们在测试申请类中所拥有的同一个端口;重要的是这些对齐。如果您在此处稍稍安全,则可以将端口移动到构建配置字段中。

回应嘲笑

恭喜这一点!我相信这是很多跟随的。让我们看看我们现在的位置:

  • 我们创建了一个TestApplication类,它允许我们覆盖我们正常应用程序将使用的任何内容。
  • 我们已经了解了如何实现自己的自定义JUnit runner来使用此测试阶层。
  • 我们制作了它,以便当我们的应用程序运行连接的测试时,它将与localhost交谈,而不是向您的公司的服务器出去。

所有伟大的东西!不幸的是,我们还没有嘲笑任何回复。如果您运行测试,您将看到很多404错误。所以让我们谈谈我们如何解决这个问题。

文件读取样板

在广泛的条件下,我们在这里有两种方法:使我们的模型方式以编程方式从模型对象中响应,或者从JSON文件中读取我们的模拟响应(如果您有关于为什么一个人比另一个人更好,请打电话给我在推特上因为我真的不知道这里最好)。我选择使用文件,我刚刚简要谈到添加的样板代码以使其发生。

您要保存以下位置中的所有文件:

app / src / debug / assets / network_files / endpoint_success.json

我选择打电话给文件夹Network_files.,但你可以把它称为你喜欢的东西。现在我们有我们的JSON文件,我们需要一种方法来阅读它们。我创造了以下内容assetrederutil.kt.文件并将其存储在我的Androidtest目录中:188博金宝电子体育频道

Object AsseTrederutil {Fun Asset(上下文:Context,AssetPath:String):String {Try {Val InputStream = Context.AsceSet.Open(“Network_files / $ AsetPath”)返回InputStreamToString(InputStream,“UTF-8”)} Catch(e:IOException异常){抛出的RuntimeException(E)}}私人乐趣inputStreamToString(的inputStream:InputStream中,的charsetName:字符串):字符串{VAL建设者=的StringBuilder()VAL读卡器= InputStreamReader的(的inputStream,的charsetName)reader.readLines(){的forEach建设者.append(it)} return builder.tostring()}}

现在我们有这个,让我们走过这些模拟。

调度员

mockwebserver使用称为a的东西调度员处理映射的服务器响应。它包括一个方法,让我们覆盖,这告诉我们请求是什么,并允许我们返回特定的模拟响应。

以下是我的调度员如何工作:

  • 它接受一个上下文,它用于从最后一步中的文件中读取。
  • 它包含一个地图属性,它将端点映射到文件名的文件名以其模拟响应。
  • 如果Dispatch方法查找所请求的端点的文件名,则将返回该映射响应。
  • 如果没有找到模拟文件,我们将返回404。

这是所有的代码:

Class SuccessDispatcher(私有Val上下文:context = strustrationRegisty.getInstrumentation()。上下文):dispatcher(){private val responsefilesbypath:map 

我把这个调度员命名了成功ispatcher.因为它只返回成功响应。如果要覆盖响应,我建议向远离终端点的静态地图转向文件名,而是公开一种方法,该方法允许您定义每个端点应该映射的内容。

在开始测试之前模拟

您需要注意的最后一件事是,您需要确保开始Mockwebserver运行您的申请。您的应用程序可能会在初始化时进行网络请求,因此如果您首先启动应用程序(这是eSpresso默认值),事情可能无法按预期工作。您可以调整ActivityTestrule以在设置方法内启动,如下所示:

@runwith(188博金宝电子体育频道androidjunit4 :: class)class mainActivitytest {@jvmfield @rule var活动特斯特雷= activitytestrule(mainactivity :: class.java,true,false)private var mockwebserver = mockwebserver()@before fun setup(){mockwebserver.start(buildconfig.port)mockwebserver.dispatcher = successdispatcher()活动特性istrule.launchactivity(null)} @After fun teardown(){mockwebserver.shutdown()} // ...}

样本

现在我们已经完成了所有这些,我们可以编写这样的自动测试,这是为自己的所有模拟数据而不是与真实用户交互:

dtautomation.

如果您想查看使用这些工具的超级基本应用程序,请随时叉这个示例项目

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

想在Okcupid加入我吗?188bet金宝搏官网我们正在招聘!