作者:廖亿富
团队:腾讯移动品质中心 TMQ
几个月前技术侧发起了一轮手机管家小火箭的重构,目的是为了更好地梳理小火箭的代码架构逻辑,方便以后更好地提高开发效率和开发质量。
下面将从测试的角度为大家一一剖析如何利用各种手段提高测试的质量与效率。
重构的架构进行了分层设计,分为了 4 层次:UI 展示层、业务逻辑层、数据层和接口层。这样子方便了代码的开发、维护,同时对于测试人员对代码分析、分层测试也提供了很多的便利,使得分层测试存在了很大的可能性。
重构并不如新功能的开发,对于开发和测试人员来说,毋庸置疑的是必须熟悉重构前的功能,这样子才能够更好地进行业务开发和测试,否则会造成一些功能上的缺失和漏测的现象出现。同时如何能够快速进行新旧功能的测试验证,也是值得测试人员思考的地方。
在熟悉插件架构和业务逻辑的可知,技术架构采用了分层设计的理念,那对于测试而言,是不是也可以进行一些分层设计的测试方式来进行测试呢。首先,对小火箭插件进行大体上的梳理。
从上图可以剖析出我们需要的测试点与需要的一些测试技术:
(1)对于接口,我们可以利用模拟插件间的接口进行验证。
(2)对于 UI 展示方面,我们可以利用手工测试或者 ui 自动化方式进行验证。但是小火箭的 UI 主要是小火箭皮肤,涉及到皮肤拖动、发射等效果,利用 ui 自动化的方式难捕捉,所以采取了最土的方法:手工测试。
(3)对于业务逻辑和数据处理,我们可以利用单元测试的手段进行更深入的测试。
(4)对于调用外部接口,我们可以利用 Hook 进行模拟外部数据,方便更好地进行测试。
经过对新功能与不变功能的分析,小火箭重构主要修改点是小火箭皮肤与逻辑的改造。对于不变功能可以采取提前测试接入(单测、插件间接口测试、UI 功能测试),而对于新功能则跟随技术架构与开发进度进行测试验证。
插件的接口主要是为了暴露接口给其他插件,方便与其他插件进行通信。以小火箭接口 A 为例:
对于插件间的接口测试,我们把小火箭当成一个黑盒子,只需要关注接口入参 (必填、选填) 和出参的正确性,对于被测对象插件内的逻辑可以通过其他手段进行测试验证。
Ø 接口协议分析:
接口文档:从接口文档中可知该接口有入参也有 RESULT 返回值,测试该接口时可以对返回值的结果进行校验。
Ø 插件间测试用例设计:
用例设计主要分正常用例与异常用例(唯一标识、非空和长度校验等)。
Ø 插件间测试用例执行:
利用 pitest 模拟插件发送请求,获取返回值并校验,同时校验是否入库成功。
插件的外部接口测试类似于上面的情况可以利用自动化方式每日进行监控,而有些接口是无返回值和难校验的,可以利用模拟接口发现 + 人工验证的方式进行验证,同样可以做到事半功倍,提高测试的效率。
程序员要对自己编写的代码负责,不仅要保证它能通过编译,正常地运行,而且要满足需求和设计预期的效果。单元测试正是验证代码行为是否满足预期的有效手段之一。
做单元测试,除了需要深知单测方法、逻辑等知识外,还需要特别熟悉每个方法代表的意义和执行的业务逻辑。在这里就不介绍单测的一些方法,仅从个人角度觉得有意思的三个方面说说单元测试的使用场景。
测试 Java 私有方法之前的思路是通过把目标类的私有方法修饰符 private 修改为 public,或者将 private 在代码里面加 public 方法来调用私有方法,这两种方式都是需要源程序的代码,会造成代码同步与维护难的问题。
经过查找,可以通过 Java 反射的方式达到 private 方法的测试。反射中的 getDeclaredMethod() 可获取公共、保护和默认(包)访问和私有方法,但不包括继承的方法。
以 getDemo(int type) 这个方法来讲如何进行 private 测试。
根据代码可知:mModelList 是已保存的事件 list,根据传入的事件类型进行遍历。所以,在进行单测用例设计时,需要 mock 住 mModelList 模拟事件 List,通过 getDeclaredMethod 进行 private 方法的调用。详细单测代码如下:
异常是阻止当前方法或作用域继续执行的问题。虽然 Java 中有异常处理机制,但是绝不能用 “正常” 的态度来看待异常。
Throwable 是 Java 种所有错误或异常的超类,包括了 Error 与 Exception。Error 是拥有指示合理的应用程序不应该试图捕获的严重问题,Exception 它指出了合理的应用程序想要捕获的条件。
常见的运行时 Exception 有如下 10 种:
案例分析:feature2RecoModel 类代码走读与测试
通过代码走读/异常测试可以发现 feature2RecoModel 方法如果 adModel.text1 非数字,通过 Integer.valueOf 会抛 NumberFormatException,会造成手管 crash。所以大家在做代码走读时,可以留意 Exception 有没有进行 try-catch-finally/throws,否则很可能出现 crash。
注:Integer.valueOf(str or num) 是把一个数字或者一个字符串转化为 Integer 类型的数据。
大家在代码走读/异常测试时可以关注异常的观察与测试,很容易可以发现代码中存在的 Crash 问题。
看下面 checkDemo 的代码是没有什么问题的,就是判断有没有本地对应的事件而已。
如果只是跟随开发设计代码的逻辑来设计用例,而不思考使用场景,是很难发现业务层次的问题,同时也对测试人员提出了更高的要求:居要懂架构、代码逻辑,更要懂每个方法的业务逻辑。
Ø 业务流程分析:
经过业务流程分析知道 checkDemo 的用处,分析 Model 数据(结构如下)可以知道有效的 Toast 事件是与 showCount、maxShowCount 和 endTime 紧密相关的。
Ø 用例设计与测试验证:
接着我们来设计 checkDemo 的单元测试用例验证逻辑:Model(过期时间<当前时间) 塞入 modelMap->调用 checkDemo 测试->结果判断。
所以,单元测试不单单是代码规范,代码 crash 等异常,更关键的是要测试人员懂得每个方法代表的意义,才能够更好地进行逻辑层的测试。
小火箭是由技术侧发起的重构,首先开发对新的架构进行梳理,测试侧对之前用例进行整理,在前期就保证了产品、设计、开发、测试与运营在整理功能上保持了一致统一性,同时也确定了修改点和影响范围。
整理了新旧功能,测试人员首先在旧功能上进行入手,对旧功能从插件接口、内部接口等方面进行测试用例准备,提前进行用例的测试。
开发人员在开发过程中,每天将代码 update 到 svn,第二天测试人员就对相应的接口进行用例设计与接口测试,与开发保持同步,及时发现代码层的问题。
在提测前组织了一轮的冒烟测试,提测后利用自动化 + 手工测试的方式不到 1 天就完成了所有功能的回归验证 + 渠道包上线前。大大地提高了测试在整个周期中所占用的时间。
小火箭渠道包已成功发布,让我们回顾一下测试方面的效果。
第一,从 bug 数量上来看:逻辑层的 bug 拦截率为 100%,其中利用白盒 + 插件接口 + 代码走读发现的问题有 7 个,冒烟测试 18 个,功能测试未发现问题。
第二,功能测试在开发提测后,仅花费了<1 天的时间过功能测试 + 上线前的测试,大大减少了功能测试在整个重构(1 个月左右)中的时间占比。
对于重构的项目,我觉得可以从研发的各个阶段入手,提高与各个角色的协同,可以更快地进行产品开发与测试的迭代。而对于测试技术、测试方法这个,可以利用被测对象的特性进行选型,怎么有用怎么方便就怎么来。
思考:如何结合自身项目更好地做好分层测试设计,并使用各种手段实现分层测试?
关注微信公众号:腾讯移动品质中心 TMQ,获取更多测试干货!