军规2 “移动”测试
当App上线之后,我们可以通过各种途径得到用户的反馈。有些时候我们会很纳闷,用户说有问题的功能,明明是我们重点测试过的,怎么可能还会有问题呢?是不是用户打开的姿势不对?
这时候很可能我们已经陷入了一个误区,觉得我们是按照用户的使用习惯来测试的,用户在使用中不可能出现这样的问题。但是我们忽略了用户使用App时的场景,也就是环境对App的影响。
相对于桌面应用,移动App最大的特点就在于移动性。用户在任何时间任何地点都可以打开App使用,这意味着App对于不同网络,以及网络变化的情况都能进行处理。
图2.1展示了iPhone上支持的网络种类。测试人员并非对于每一种网络都需要测试,如何确定需要测试的网络,取决于App在网络上获取什么样的信息。
图2.1 iOS上不同的网络状态图标
(1)如果App只是通过网络访问服务器,那需要考虑的主要就是高速和低速网络之间的差别。因此只要测试Wi-Fi、3G/4G/LTE、EDGE/GPRS以及飞行模式就可以了。
为什么需要单独测试飞行模式呢?因为对于联网的App,不仅需要考虑到有网络环境中用户的使用,在无网络的情况下也要保证App不会出错,例如App崩溃等。
当App需要大数据量传输数据时,很可能需要把3G和4G/LTE的测试分开,充分模拟真实用户使用的场景。
(2)如果App需要在不同的网络环境里得到认证信息,例如移动运营商的信令,那测试人员就需要对于不同的信令获取方式进行单独的测试分类了。比如说,如果App在4G/LTE的环境下进行的验证方式不同于3G环境,就不能把这两种网络状态当成一种情况来进行测试,而是要分别进行测试。
哇,这么多种网络环境,怎么进行测试啊?需要买这么多种SIM卡吗?不对啊,EDGE和GPRS可没有对应的SIM卡,现在什么SIM卡能支持这两种网络啊!是这两种网络环境一定要一起测试吗?或者需要专门的设备来测试?
其实,我们大可不必为网络环境而忧心忡忡,因为在程序开发和自动化测试中可以使用Mock技术。通过使用Mock可以从服务器端返回一般需要真实网络环境才能得到的response应答,这样App就可以直接处理信息,而不用非得连接到真实的网络环境或者是非得处于特定的状态下了。使用Mock这种方式减少了在开发和测试过程中由于需要真实环境而对于网络、设备和资源的投入。
那具体如何使用Mock技术呢?
(1)对于不用在网络上获取信令Token的App,可以直接在代码里对App包进行标记,比如打上测试的标签,并且在向服务器发送请求的时候带上这个标签,这样服务器就可以根据这个测试的标签,判断出客户端是测试的App,从而对网络环境进行模拟并运行对应的Mock代码,延迟把产生的应答response发送回App,这样就可以模拟低网速下的网络环境了。另外,可以通过控制延迟时间的多少,模拟真实环境中不同网络速度的网络状况。
(2)对于需要在网络上获取信令的App,基本过程和上述一致,只是需要在Mock代码中添加生成信令的代码,从而使服务器在返回应答时把信令告知客户端,从而绕过真实环境中的网络验证环节。
如果你还有疑问,猜想开发人员会不会因为增加了工作量而不同意做这些工作呢,那么大可放心,因为这些工作只是一次性的环境准备工作,对于整个团队来说都是必要的。开发人员也更希望在编码的时候就确保App能应对各种网络环境,而不用等出现了缺陷,花了很大力气之后才发现是网络环境的影响,而且还要得东奔西走,找不同的网络来验证修复;另外,业务分析人员也需要在不同的网络环境下设计用户的体验和交互方式。
目前也有不少工具可以帮我们快速搭建Mock环境,例如Mountebank、Charles、Apple Network Link Conditioner和moco。笔者比较常用的是moco,不仅是因为moco是2013年Oracle Duke's Choice获奖作品,而且因为moco搭建简单,如果App不涉及获取信令的验证,以及与其他Service的集成,测试人员按照说明手册自己搭建一个Mock环境也是很快的。这样测试人员还可以参与后期Mock环境的维护,确保Mock的真实性和准确性(如图2.2所示)。
图2.2 配置文件中设置的response以及从页面中看到的结果
下面先简单介绍一下如何快速搭建moco环境(以Mac OS X为例)。
(1)首先下载moco的独立运行的jar文件(地址如下)。
http://repo1.maven.org/maven2/com/github/dreamhead/moco-runner/0.9.2/moco-runne r-0.9.2-standalone.jar
(2)打开任何一个文本编辑器,比如说Sublime Text。
(3)输入以下的内容,这些内容将作为moco的配置文件,在moco运行时被读取;这些配置文件的作用,是用来向客户端返回被Mock过的服务器的response(如图2.3所示)。
图2.3 设置moco配置文件内容
[ { "response" : { "text" : "Hi,移动App测试的22条军规的读者" } } ]
(4)保存成文件,并命名为“22rules”,并放置于moco jar文件所在的同一目录下(如图2.4所示)。
图2.4 把保存的“22rules”和moco jar文件放在同一文件夹下(比如“workspace”)
(5)在命令行工具,如“Terminal”下打开“workspace”这个文件夹。
(6)输入命令“(java -jar moco-runner-0.9.2-standalone.jar start -p 12306-c 22rules)”来启动moco,以下是moco的运行提示(如图2.5所示)。
图2.5 moco运行后的提示信息
(7)在浏览器中打开http://localhost:12306/就可以看到网页上显示之前在“22rules”里设置的信息:“Hi,移动App测试的22条军规的读者”(如图2.6所示)。
图2.6 在浏览器中能看到之前在moco配置文件中输入的内容
(8)当然,真实的场景不会这么简单,特定的请求request需要不同的response。这时就需要对moco配置文件改成如下内容(如图2.7所示)。
[ { "response" : { "text" : "Hi,移动App测试的22条军规的读者" } }, { "request" : { "uri" : "/22" }, "response" : { "text" : "我是特定的response" } } ]
图2.7 对特定的请求request设置特定的应答response
(9)打开http://localhost:12306/22查看结果,会发现针对不同的请求request,返回的response也是不一样的(如图2.8所示)。
图2.8 特定的请求request返回特定的应答response
(10)如果多个配置文件需要一起读取,那怎么办呢?这时就需要多个配置文件。下面来创建另外两个配置文件“another”和“combined”,它们的内容如下(如图2.9和图2.10所示)。
图2.9 “another”配置文件的内容
图2.10 “combined”配置文件的内容
“another”配置文件的内容如下。
[ { "request" : { "uri" : "/another" }, "response" : { "text" : "我是另一个特定的response" } } ]
“combined”配置文件的内容如下。
[ { "include" : "22rules" }, { "include" : "another" } ]
(11)这两个配置文件也需要和之前的“22rules”以及moco jar文件在同一文件夹下(如图2.11所示)。
图2.11 所有文件都需要放置在同一文件夹下
(12)在命令行(“Terminal”)里运行“(java -jar moco-runner-0.9.2-standalone.jar start-p 12306-g combined)”(如图2.12所示)。
图2.12 moco读取多个配置文件运行后的提示信息
(13)再次打开http://localhost:12306/, http://localhost:12306/22,以及http://localhost:12306/another来查看同时支持多个不同配置文件的运行效果(如图2.13所示)。
图2.13 moco同时支持多个配置文件的读取和运行
(14)关于更多的moco的进阶使用和配置,请参考GitHub上moco的文档。
当然,有些特殊的网络环境我们是没有办法很容易地进行模拟的,例如前几年2G SIM卡的cmwap会抛弃一些@@http自定义头,现在的移动3G SIM卡丢包率很高等场景。对于这些场景的测试,我们还是需要使用真实的SIM卡,在手机等设备上进行测试。
现在让我们回到本章最开始的那个问题,你可能会说,我都按照你所说的在不同的网络状态下进行了测试了,可是用户还是会在执行过测试的那些场景发现我们没有发现的bug,这是为什么呢?
好,让我们再想一想测试人员所在的测试场景和用户的使用场景有什么不同呢?用户都是在什么样的环境中使用呢?咦,用户好像是不会像测试人员一样一直在办公桌前,在网络环境很好很稳定的区域使用App的!
没错,测试人员测试的仅仅是在特定的网络环境下App的表现,在网络切换的时候,App会如何处理测试人员是完全不清楚的。所以不要以为App在不同网络环境下表现正常,在网络切换的时候就不会有问题。下面还是拿需要在网络上验证信息取得信令的App来做例子(如图2.14所示)。
图2.14 获取移动网络信令App的结构示例
试想在App使用过程中需要在3G/4G网络上取得SIM卡注册后的信令,通过这个信令用户可以直接进行支付和延长合约等操作;在无线网络或者无网络的情况下,因为不验证SIM卡注册信息,所以无法进行相应的操作。但是当用户从一个有3G/4G信号的地点移动到一个没有信号(或者有无线网络连接)的地点,如果App处理不好,就会出现虽然App拿到了信令,相应的菜单显示可用,但是实际用户不仅无法成功操作,甚至还会出现异常的信息提示。
再试想一下,如果App具有支付功能,在网络不好的情况下,用户支付了订单,突然网络中断,用户的订单信息还是未完成,但钱已经从用户账户上支出了,这就不是一个小的问题了。相对而言,对于银行类的App,如果用户在网络不好的情况下支取了资金,但是用户账面金额并没有相应地扣除,银行损失的就不会是一笔小钱了。
对于网络异常的提示信息也需要人性化的设计,只告诉用户“HTTP 500 Internal Error”这样的消息对用户来说不仅没有任何帮助,反而会加剧用户的挫败感和不满情绪。图2.15就展示了这种不恰当的错误提示信息的真实场景。
图2.15 不恰当的错误提示信息
在网络出现异常,程序无法进一步处理的情况时,App应该明确告诉用户应该怎么操作,例如在网络连接不上的时候告知用户:“网络无连接,请稍后再试。”或者在网速很慢的时候提示用户:“当前网速很慢,可能会影响您的体验。”
而在后台,则需要定时刷新,避免在网络恢复的时候,App依旧显示网络异常时的提示信息,也避免用户需要不停手动刷新。当然,在多次尝试失败之后,可以放弃刷新尝试,改为让用户手动刷新来减少对于网络流量和电量的消耗。
对于视频播放类App,也需要验证在网络进行切换,比如Wi-Fi切换到4G或者3G网络时,对应播放的视频清晰度是否也会进行对应的切换。
当然,毕竟任何模拟都是替代方案,为了能模拟真实的网络环境和网络切换,走出去,“移动着”测试不失为一个选择。在真实环境的测试过程中,测试人员也会注意到更多之前忽略的用户使用的小细节。让我们在移动App测试的时候“动”起来吧!