机器学习以及深度学习技术迅猛发展,很多行业已经从中受益,其中软件质量工程也从中收益良多。机器学习的很多思想和方法可以被用来解决目前软件测试领域的多项难题。本文将会从测试设计、测试执行和测试结果分析三个维度来探讨目前机器学习在其中的应用与创新。其中会涉及基于机器学习来识别 GUI 控件以提高 GUI 自动化测试的效率与稳定性、基于路径权重来优化测试设计、基于 kNN 之类的算法对批量失败测试用例做自动分类处理等多个案例,希望通过本文可以引发你对机器学习在软件测试领域应用的更多思考。

  人工智能应用概述

  自从 2016 年 AlphaGo 以 4:1 战胜了围棋九段李世乭,人工智能的威力在公众面前得到了充分的展现。这种基于改进的蒙特卡洛树搜索、残差卷积神经网络的强化学习系统首次向公众展示了其超越人类智慧的强大的力量,也使 AI 变得更加广为人知。之后各行各业都出现了大量的基于 AI 的产品与应用,其中以机器学习,自然语言处理,计算机视觉和专家系统为支撑的应用层出不穷,大到金融分控模型,无人驾驶,舆情监控与分析,小到智能美颜,智能音箱,无处不见 AI 的应用。这类应用基本都是通过软件来实现的,那在软件研发的过程中,AI 技术是否也有其应用场景,并可以帮助来提高软件研发的效能呢?那么我们今天就一起来探讨一下机器学习在软件测试领域的应用。

  软件测试技术的局限性

  当前普遍采用的传统软件测试技术主要有以下三个方面的局限性:

  从测试的执行层面来看,GUI 自动化测试的开发效率与维护成本高居不下。这个主要表现在 GUI 控件识别上,当界面发生变化,或者控件属性发生细微变化的时候,都会引发很多自动化测试用例的维护工作量,这也正是自动化测试无法真正成为“银弹”的一个主要原因。

  从测试的设计层面来看,测试覆盖率的鸿沟随着产品功能点的增长而不断放大。不知道你没有注意到,做软件产品研发的企业都有一个普遍特点,就是产品迭代的初期,一般研发的效率都比较高,但是随着产品规模的不断扩大,软件功能的逐渐增多,软件研发的效率会变得越来越差,有时候很小的改动都会引发大量测试需求。这个主要是由于随着软件生命周期的增长,功能点越来越多,因为新的功能与现有的功能进行交互,当功能点的基数很大的时候,就会引发所谓的“蝴蝶效应”,因为这个过程中测试只能线性增长,这中间就会存在大量测试无法覆盖的盲区。为此,在快速迭代持续交付的今天,即使已经普遍采用自动化测试技术,软件测试人员依然面临着前所未有的压力。下面的图 1 很好展示了这个现象。

  

image

  图 1:测试覆盖率的鸿沟

  从测试结果分析的角度来看,失败测试用例分析并进行分类的工作量是很大的,而且时间成本也很高。注意这里的”分类”仅限于指将失败的测试用例分配给某个开发组来后续做进一步处理。由于互联网产品的自动化测试大规模普及,所以自动化测试用例的数量往往比以往任何时候都多,像 eBay 这样的大型全球化电商,全回归自动化测试用例的数量会达到好几万的数量级,这个时候,哪怕只有 1% 的测试用例失败,那么需要分析的失败测试用例的绝对数量也是好几百,可想而知这个如果完全基于人工来对失败用例进行分类分发的工作量是比较大的,很难在分钟级别完成,这就势必拉长了整个测试的周期,降低了迭代速度。

  针对上述的三个局限性,接下来我们来看看如何利用机器学习技术来优化测试的过程。

  机器学习在 GUI 自动化测试执行领域的应用与创新

  机器学习在 GUI 自动化测试执行领域的应用有很多种不同的思路。这里我介绍其中最主要也是具有实际落地案例的应用。

  第一种是通过控件的统计学特征来识别 GUI 对象,以此来克服 GUI 控件识别的稳定性难题。早期 GUI 的自动化测试中有一种所谓的“低级录制“和”虚拟对象“功能,是指自动化测试的回放执行是通过页面对象像素的比较以及相对位置关系来完成的,也就是说是通过控件的像素比较来确定页面对象的,这种技术虽然简单直接,但是其稳定性是个大问题,而且也无法应对今天的终端设备分辨率的多样性。那么基于统计学特征来识别 GUI 对象则是这个方法的升级版本,可以顺利解决稳定性以及应对不同分辨率的难题,同时当控件的显示发生变化的时候,依然可以做到较高的准确识别率。

  那基于统计学特征的 GUI 对象识别的原理到底是怎么回事呢?这里举个简单的例子你应该就能一下子明白了。比如现在有个”OK“的按钮,那么这个按钮的深色像素(OK 的字体部分)和浅色像素(按钮的背景色部分)所占的百分比我们是可以统计计算得到的,假定是 8:92,那么当这个按钮的 ID 或者 XPATH 发生变化的时候,或者界面的大小发生变化的时候,再或者界面的配色发生变化的时候,这个深色像素和浅色像素的百分比是不会发生变化的,那么这个时候我们就可以通过这个百分比来唯一确定这个页面对象了。这个百分比就是统计特征值,当我们综合应用多个维度的统计特征,尤其是高阶统计特征的时候,我们的控件识别率就会非常稳定。

  目前网易公司的 AirTest 就是利用了类似的技术来完成基于 AI 的控件识别的,并且能够很好地应对游戏测试中的对象识别。爱奇艺则更进一步,他们开发的 Aion 更是在控件识别之前利用机器学习和机器视觉对软件界面做了图像切割和子元素提取,进一步提高了页面对象的识别率。

  第二种方式更加直观,即直接通过视觉外观来查找页面对象。比如测试代码中可以直接指定点击“购物车“而无需事先提供购物车图标的 ID 和 XPATH 等定位信息。比如下面的代码(图 2)就是直接通过”购物车“来完成点击操作的,其中完全没有给出传统的定位器信息(购物车图标的 ID,XPATH 等)。

  

image

  图 2:直接通过“ShoppingCart“来点击购物车图标

  这个的实现原理就是利用机器学习来训练模型,我们会收集市面上所有的购物车图标作为模型训练的样本数据来完成模型的训练(图 3),然后就可以直接这个模型来实现各种购物车图标的识别了。目前移动应用测试工具 Appium 的一个 AI 插件 Appium Classifier Plugin 就已经实现了类似的功能,并且这个机器学习模型的训练数据是开源的,它可以告诉我们,图标代表什么样的内容。我们可以使用此插件根据其外观在屏幕上查找图标,即通过视觉外观查找元素。这种方法比传统的页面对象定位灵活得多,因为 AI 模型经过训练后识别图标时无需任何上下文,并且不要求进行图像样式的精确匹配,这意味着使用 AI 模型查找“购物车”图标可以跨应用程序和跨平台工作,而无需担心各个平台的细微差别。

  

image

  图 3:用作训练样本集的各种购物车图标

  机器学习在测试设计领域的应用与创新

  上面讲述的利用机器学习来对 GUI 控件进行智能化识别虽然在自动化测试执行层面带了很大的帮助,但是此种类型的应用对于机器学习来讲,似乎有点“杀鸡用牛刀”了。因为如果我们能将机器学习用在测试设计上,或者说用在缩小测试范围上,那么机器学习将会发挥更强大的作用,此时机器学习就像是变形金刚中的能量块,能够发挥举足轻重的重要作用。可以这样说“机器学习和测试设计结合将成为交付真正测试自自动化的催化剂”。

  

image

  图 4:机器学习在测试设计中将发挥更大的作用

  具体来讲,这里有两种完全不同的思路来应用机器学习技术来帮助测试的设计。

  第一种思路是通过机器学习来训练一个机器人,使其成为某个领域的测试专家。比如通过大量的训练,“登录”测试机器人可以比人类更好地对登录功能进行全方位的测试,“订单“测试机器人可以进行全方位的订单系统测试,这种类型的机器人有点类似于专家系统的概念,能够根据训练时积累的场景来展开测试。并且你会发现这样一个事实,几乎所有的应用都是有共性的,比如都有登录功能,都有搜索功能,都有用户管理功能等,这也就是说我们可以通过构建有限种类的机器人来支持大多数软件的测试设计工作,而且构建的测试机器人数量并不会随着应用数量的增长而增长。相反,当构建了一定数量的测试机器人之后,这些机器人就能应对大量应用的测试了。目前比较知名的 Appdiff 就是利用了这样的思路来构建 AI 测试工具的,并且通过自动化地比较前后多次的执行结果,比如 GUI 的变化,页面性能的变化等来自动化地发现潜在问题(图 5)。

  

image

  图 5:通过自动化地比较前后多次的执行结果来发现软件中的异常

  第二种方式是先构建被测系统的模型,这里又可以分为两种不同的种类的模型。一种是基于被测系统页面流转的模型(图 6),这个模型反映的是被测系统各个页面之间的跳转关系,比如 A 页面可以到 B 页面,然后 B 页面可以到 C 页面,那么这个三个页面就对应图论中的三个节点,然后 A 可以到 B,那么 A 到 B 之间就存在一条有向边,同样的,B 和 C 之间也有一条有向边。另一种是基于后端微服务架构的系统架构图(图 7),反映的是后端各个微服务之间的相互调用关系网络。

  有了这种基于图论的模型后,接下来会通过应用的后台日志系统来分析页面和页面之间的跳转,或者是微服务和微服务之间的调用,这个过程通常需要借助大数据分析系统的能力,通常使用 Hadoop 和 MapReduce 来完成,然后对于页面模型每检测到一次页面跳转,就将有向边的权重加一,如果是微服务模型每检测到一次调用,也将有向边的权重加一,然后后面测试路径的选择就会优先覆盖哪些高权重的路径,当测试时间资源有限的时候,就只会覆盖那些高权重路径,以此来体现软件测试中“基于风险驱动“的设计思想。同时,我们还可以考虑利用图论的算法来合并多个模型来形成一个更大的模型,下面的图 8 给出了示例。

  

image

  图 6:基于页面流转的图

  

image

  图 7:基于微服务调用关系的图

  

image

  图 8:利用图论的算法来合并多个模型来形成一个更大的模型

  进一步设想,如果我们将上述的测试设计和测试自动化执行结合起来,这样就能完成一条龙的测试设计和执行,并且整个过程并没有人工的干预。可想而知,这样将可以最大化利用机器的空余时间来完成大量测试用例的设计和执行,以此来填补测试覆盖率的鸿沟。

  机器学习在测试分析领域的应用与创新

  最后,我们来看一下机器学习在测试结果分析领域的应用与创新。前文中我们提到失败测试用例分析的工作量很大的,而且时间成本也很高,那么我们是否可以利用机器学习来对失败测试用例进行自动化的分类呢?答案是肯定的,而且这种基于特征值的分类问题正是机器学习的强项。

  具体的做法是选择失败测试用例的多个特征值,然后基于 kNN 之类的算法来完成失败用例的自动化分类。这里特征值的选择将直接影响分类的准确性,同时需要事先标注大量的已知失败用例的分类结果来对 kNN 进行训练。kNN 算法的基本原理是“近朱者赤,近墨者黑”,由你的邻居来推断出你的类别。系统的整体架构设计如图 9 所示。从图中可见,我们选择了 Exception Name,Exception Message,Stack Trace 等作为了我们的特征值。

  这里需要要特别注意两点,一是我们必须确保输入日志的完整性,只有当日志包含了完整准确的信息,才有可能基于此做出准确的分类,这种对日志完整性的要求其实可以看做可测试性需求,在设计阶段,作为资深的测试工程师就应该需要关注这方面的内容。二是在 kNN 算法模块的前面,我们放置了一个 Hard Rule 模块,这个模块和机器学习没有任何关系,而是基于日志中硬编码的规则来对失败测试用例进行分类,比如假定日志中抛出异常的模块是 A,那么我们就应该将这个失败用例自动分配给模块 A 的开发团队去做进一步的分析,由于这里采用的是确定的硬编码,所以分类的准确率在前期就会很高。而那些无法通过 Hard Rule 完成分类的用例才会进入到 kNN 的算法模块,而 kNN 模块的分类准确性在很大程度上取决于训练样本的数量与质量。

  eBay 就是通过这样的系统来完成日常全回归过程中失败用例的分类,基本每天会自动完成超过 200 个失败用例的分类任务,项目前期由于样本数量的局限性,所以前期的准确率在 70% 左右,后期随着样本数量的增加,准确率维持在 90% 左右。

  

image

  图 9:基于 kNN 和 Hard Rule 的失败测试用例分类系统

  进一步,我们可以想象,如果将机器学习应用到性能测试报告的分析上又会是什么样的效果。这个和目前 AI 在医疗诊断领域的应用非常类似,只是医疗诊断领域的输入是各种化验报告,而性能测试分析领域的输入则是各种性能指标,然后基于机器学习的算法来发现这些指标之间的连带关系,以此来确定系统的性能瓶颈。

  总结

  本文介绍了机器学习在测试执行,测试设计以及测试结果分析领域的典型应用场景,并希望由此抛砖引玉,激发读者更多关于人工智能在软件测试领域应用的落地实践与方法。