和开发一起写代码,让测试左移起来

一、写在前面的话

互联网产品的迭代速度之快,各位都深有体会。做为产品质量的保障者,测试人员经常为测试时间不足而烦恼,如何打破现状来让现在变得更好一些,这是我们一直在思考的问题。软件工程中有提到测试人员越早的介入到研发的流程当中,就可以越早的发现问题,从而降低发现问题的成本。因此”左移”变得非常的有必要了起来,当然左移的方式有很多,例如前几天拜读到的《聊聊测试“左移”那些事》这里面主要讲测试人员通过把控需求来达到左移的效果,而我今天要谈的是自动化的左移。

二、我眼中的自动化左移

想想之前我们做的UI自动化是怎么做的呢?在版本提测之后,我们开始写自动化,这样自动化的主要功能就变成了回归和冒烟。我这里我想说的是在开发写代码的时候,我们也开始写用例级别代码,在开发定义了界面布局后,我们就可以完善具体代码,待开发提测时,我们就可以运行我们的用例来进行测试了。如何才能做到这一点呢?那你就需要让你的自动化用例高度的抽象出来,这里呢,我的同事yoyo建议我们使用一种基于关键字驱动的用例方法,我们首先来看看类图:

稍微解释一下这些模块

Base Test

所有Test类的基类,也就是测试用例的基类,里面实现ActivityTestRule来启动Activity,如果有需要的情况下可以实现BeforeClass和AfterClass,这两个在整个命令的运行周期内只在开始和结束的地方执行一次。

  用例Test 

具体的测试用例的实现类,这个可以理解为一个测试集,每个类中有若干test函数,每个函数就代表一个测试用例,用例的写法采用关键字驱动的方法。

   Key        

用枚举定义着所有的关键字。

Command 

接口类,供Word实现execute(Obj)的方法。

FrameCommand

基类,供Word层来继承,里面只封装了一个execute(Key, Obj…),主要用在AW中调用KW的实现;这里需要注意和Command接口中execute的区别。

  Word层     

即图中Login、Enter**Page等,需要实现Command接口中的execute函数,同时继承自FrameCommand,解释为什么是Word层,这里需要把这些实现抽象成ActionWord(简称AW)、KeyWord(简称KW),而这两者的区别就是,KeyWord中实现可复用的一些场景,ActionWord中可以包含KeyWord,实现一些很少被复用的场景。

TestContext

将Key中关键字和具体的Word实现的函数进行关联,构造一个map,使得直接通过execute关键字就能调用起对应的函数。

具体实现的代码我先不详细解释,我们先来看看使用这套框架后,之前实现同样功能代码写成了什么样子。

老代码

新代码

可以看到,测试用例(这里认为一个test***函数就是一个测试用例)这一层我们做了高度的抽象,在testPublish这个函数中没有任何与开发源代码或者是资源id有关的信息了,这里的Key.EnterPublishPage就是我们的关键字,具体的实现在EnterPublishPage这个AW的函数中。

三、封装框架

当然为了保证UI自动化的稳定性,我这里也对框架进行了再封装。这里我使用了谷歌推荐使用这两款框架Espresso和Uiautomator,有兴趣可以看看谷歌的这两篇原文:

那么两个框架同时加入到我们的测试工程应该如何去整合代码结构内,这里我自己使用这样的结构,觉得不错的可以稍微看看,首先先看下类图:

看完类图后可能有些人已经看出来啦,没错这里使用了简单工厂模式,具体的Word层来使用工程加工出来的对象,具体的工具封装内容包装在FrameUiautomator和FrameEspresso里。

这里主要说下针对Uiautomator的封装,如果之前读过我写的《手把手教你搭建安卓自动化框架之UIAutomator》的“如何更高效”章节,那么里面的一些思想应该比较清楚了。

主要优点

1、页面跳转或者异步加载延迟出现的界面,无需再单独使用sleep;2、对于系统随机出现的可能会影响App界面的一些因素(例如Android6.0的授权弹框、电话呼入),无需再单独处理;3、对于App中随机出现的可能会遮挡正常界面的一些弹框,无需再单独处理;4、所有调用封装后框架的操作,都会记录日志;5、框架本身有断言能力,如果在框架处理异常情况后还找不到指定控件,这时候会截图并且断言;6、如果需要替换框架或者框架升级,可以使用最小的成本来框架层进行改动,而不需要改动用例层和Word层。

当然和之前的不同就是里面也借鉴了关键字驱动的思路,有兴趣可以看看代码。

四、结果展示

上面主要讲的是UI自动化的一些行为操作,关于断言的问题,我这里不想说太多,BVT做到界面上的UI元素的检查,以及整个流程是否可以完整的走下来就可以了,如果需要验证数据正确性等一些复杂的内容,可以使用TMQ.jar的这个组件去验证,具有参考:https://github.com/r551/TMQ 。我这里说说UI自动化如果失败了,我们怎么排查问题?其实很简单我这里做的就是日志+截图。

日志系统最关键的是打日志的时机,这里我把它埋到了BaseTest的execute()中,这样每一次的用例调用AW或者AW中调用KW,都可以记录下来,同时也埋到了框架的具体实现函数中,这样框架只要操作就会记录下日志。这里有个小的技巧,我在打印日志的地方调用了下面的函数:

Thread.currentThread().getStackTrace()[3].getClassName();

这样就可以记录下当时调用Log函数的当前的类的名称了,这里可以看下我输出的log的样子:

是不是比较齐全了,基本上所有你想知道的信息都可以通过log内容来获得了。下面说说截图,截图和log的整体思路一样,会在一些关键节点埋点同时也支持手动调用。因为我的工具框架是支持自身断言的,因此我在工具框架这一层断言的时候会加入截图,其他地方如果你需要特别关注的时候,也可以手动调用截图触发。

上面的图是不是非常直观,当我们的用例出现异常错误的时候,直接通过log和日志即可定位到问题的所在。测试结果最终对接了内部的持续集成平台和结果展示平台后是这个样子:

保证了编译器中的结果和结果展示平台中显示的情况一致。

五、实践应用

我们来看看针对新老需求如何应对。

如果是新需求的情况下,我们在需求确定的情况下就可以先组织自己的用例了,具体实现依赖开发的word层的代码可以先空着,待开发确定之后,我们就可以及时的完善我们的word层,这样不用等到开发提测之后,我们才开始设计我们的自动化测试用例。

对于老的需求变更,同样也是,首先可以看之前的用例中的关键字是否有可复用的东西,如果可以直接复用,那就继续用,如果有新的步骤加进来,那么只需要加入对应的关键字即可,和新需求的做法一样,同样在开发提测之前完成用例的编写。这里闲贝在版本迭代中,有一个发布页面的UI变更,由两个页面合并为一个页面,部分小地方也有所修改,如下图所示:

改成了:

然而在新版改版后,用例根本不需要变化,还是保持之前的样子,只是把对应的word层中的一些代码进行了一些细微的调整。

六、会有收益吗?

在整个方案启动之前,我就在思考这个问题。那么这个做出来后究竟会有收益吗?究竟有没有收益,需要分析后才能知道,于是针对最近的一次版本做了一个简单的bug分析:

从数据中可以看到,的确有一部分的bug是可以在左移阶段被发现的。这里分为BVT级别的用例和详细模块的用例。BVT级别用例来限制开发的提测,提测前开发自己去运动这部分用例,通过才可以提测;具体功能级别的详细模块的内容用专门针对这个版本修改或者新增的新功能。

整个方案在实现后,只勉勉强强在一个版本中进行了实践,因为某些因素,项目被叫停了,唯一的这次实践也是在一个相对不正规的不完整的版本上做的,即便如此左移实践以来共发现6个有效bug,这也是我在标题中打了一个问号的原因。虽然最终有些可惜,但是整个过程中还是学到了不少东西,拿出来和大家进行分享,希望能帮助到其他人。

 

 

版权所属,禁止转载

1,594 0 33

发表评论