精准测试--准确性测试

自动化测试技术14:精准测试原理简介与实践探索

一、精准测试的动因


小时候大家应该都玩过一个游戏,游戏很简单,就是找不同,在规定时间内两幅图直接的差异点找到就算赢,越快越好,如果色块数量少的时候事情很简单,但是如果像下面这样呢?

图片

这时候我们会有在综艺节目"最强大脑"中的渴望。上面的色块就好比我们要测试的程序,一面墙相当master分支的代码,一面墙相当于dev分支的代码,而dev改了哪些?差异在哪里?影响到的范围是多少?我们要测试的范围?

以求达到一种精准测试的程度。

在软件测试过程中,也面临这样的问题,软件精准测试这一理念之所以产生,主要是基于如下的6个方面的考虑:

  • 测试过程和规范无法满足要求

  • 项目验收缺少具备公信力的手段

  • 传统的手工测试效率较低

  • 测试与开发的断层

  • 新技术架构的挑战

虽然测试流程很规范,但是软件质量还是不如意

图片

随着测试行业的发展,软件测试做得越来越规范,但大部分的测试还是基于对业务的理解,与真实业务数据还有差距,准确性难以保证,测试结果无法精确的对软件质量进行定义和判断,系统上线后,问题开始暴露出来,使用体验差,更有甚者造成巨大的经济损失。归根结底,就是因为测试不充分,没有引入精准的测试分析,仅依靠测试经验是根本无法判断的。

软件项目验收缺少好的运行检测手段,检测结果缺少技术公信力

图片

软件是拿来使用的。虽然软件项目验收过程中验收的内容比较多,包括合同约定内容、技术协议、开发文档、产品文档、用户文档、程序代码等,但客户最关心的是他们的业务能否真的在系统中落地运行,并且运行良好,单凭投入少量人力进行业务功能的验证,抽样的检测结果不代表软件全部,可信性不具备技术公信力。

传统的手工测试,测试执行无法精准量化控制,测试效率比较低

图片

使用传统的手工测试,采用的是基于人工评定的黑盒测试方法,打造高可靠性的软件产品需要投入大量人工成本。由于测试执行无法精准量化控制,凭主观定性评价结果为主,对人力经验依赖大,人员变动情况大,质量抖动厉害,看不到明确测试差距和量化目标。虽然在不断的执行测试,但缺陷发现率并不高,无效的测试消耗了大量的测试成本。

测试人员不能精准把握缺陷现场,与开发人员协同工作困难

图片

缺陷处理的一般流程是:测试人员执行用例,发现缺陷就提交缺陷系统,开发人员看到缺陷,进行重现或远程调试。如果测试给开发提供的测试结果都是比较模糊的功能逻辑描述,重现缺陷需要花费大量的时间。如果测试人员采用了精准测试技术,通过执行的用例就可以找到对应执行的程序代码块,这样解决问题就会快很多,开发人员和测试人员之间的协同工作就会轻松好多。

分布式、微服务架构,软件越来越复杂,测试挑战性越来越大

采用分布式/微服务架构,使软件系统越来越复杂,测试的挑战性越来越大,采用传统的测试方法执行测试,系统质量也难以保证。

在移动互联网大力发展时代,软件开发对质量要求越来越高,而迭代开发要求项目周期越来越短,快速的版本验证面临挑战。

理论上,我们全面的测试覆盖,肯定就就可以保证,那么~你真的有那么多时间去全覆盖吗?再者,你确定你真的覆盖到了被测代码?也就是相当于魔方墙上的每个色块,实际在黑盒测试的过程中很大程度上取决于测试人员的经验,主观性很强,这样就很可能漏测,发布后出了问题就又要开撕了。。。

这个时候就渴望有这么一个"最强大脑"

  • 眼过去就可以看出差异点(本次改动的逻辑)

  • 脑海中就有了差异的影响范围(缩小需要测试的范围)

  • 再一扫就看出哪些测试覆盖到了(确认测试覆盖率)

二、精准测试体系介绍


精准测试是一种可追溯的软件测试技术,最强大脑的核心是数据与追溯。

从字面理解,精准就是非常准确。非常准确需要用数字说话。

在测试领域,精准测试是一套计算机测试辅助分析系统,对测试过程的活动进行监控,将采集到的监控数据进行分析,得到精准的量化数据,使用这些量化数据进行质量评价,利用这些分析数据可以促进测试过程的不断完善,形成度量及分析闭环。精准测试是一种可追溯的软件测试技术。

图片

数据与追溯

图片

精准测试的核心思想就是使用非常精确和智能的软件来解决软件测试的问题,从根本上引领从经验型方法向技术型方法的转型。质量的评估不再靠经验,而是通过精准的数据来判定。

精准测试没有改变传统的软件测试方法,区别只在于,由软件去采集测试过程执行的代码逻辑及测试数据的过程,自动建立测试用例与程序代码之间的逻辑关系。在测试过程加入软件的采集过程,可以形成正向和逆向的追溯。

通过正向追溯,开发人员可以看到测试人员执行用例的代码细节,以方便进行缺陷的修复,测试数据可以直接为开发调试提供依据,快速定位并修复缺陷。

通过逆向追溯,测试人员通过修改的源代码快速确定测试用例的范围,极大减少回归测试的盲目性和工作量,快速修订测试用例,达到测试覆盖率最大化。

三、精准测试的关键特性

精准测试系统的业务架构:主要包括变更对比分析支持风险识别,用例和代码的双向追溯支持用例挑选,测试覆盖可视支持测试评估,基于覆盖率的用例补充和用例精简四个部分

变更风险识别

基于变更支持测试风险可视化,支持RBT测试落地

用例和代码双向追溯

执行一个测试用例以后,精准测试通过程序自动的记录和显示这个测试用例执行的代码。如果测试人员关注某一些代码行,它可以追溯出哪些用例在执行过程中运行过这段代码。

智能回归用例筛选

根据代码的变动范围来直接精确的定位需要回归的用例,这样使回归测试所需的时间更短,回归的范围更准确。

测试覆盖率可视

精准测试覆盖率形式多样,最高支持标准MC/DC(修订的条件/判定覆盖)的100%覆盖率要求。

软件测试示波器

在功能测试过程中自动分析程序运行的一些数据指标,以波形的形式进行实时输出。示波器是一种实时的监控,实时的计算测试过程数据并展现。

软件缺陷快速定位

根据缺陷与用例的对应关系,快速找到执行用例对应的代码行。

四、精准测试方案的实现


根据上节的关键特性,我们可以设计出如下的一种精准测试体系。

1、精准测试体系的组成:

图片

精准测试体系主要以持续集成平台、统一测试平台和测试监控分析平台为测试能力支撑。

通过持续集成完成代码的构建编译、静态代码扫描和测试环境部署;

使用统一测试平台实现自动化测试回归;

通过测试监控分析平台,精确、详尽的记录测试用例运行的情况,提供大量原生分析性数据,进行事后的缺陷分析、追踪,建立测试用例与程序代码的关联,实现测试用例和程序代码的双向追溯,真正实现数据化的测试管理。

双向追溯

精准测试的核心流程就是通过测试监控分析平台实现测试用例和程序代码的双向追溯。

图片

在测试监控分析平台的帮助下,实现测试用例和海量的代码执行信息自动关联,精确到函数级别及代码块级别。测试人员可以知道测试用例到底测试了哪些功能,覆盖了哪些代码。

图片

上图就是测试用例到被测代码的正向追溯,通过正向追溯可直接在代码级定位测试现场故障和缺陷逻辑,并提供最后运行的时序数据;通过正向追溯自动记录产生功能对应的详细设计实现,辅助软件解耦和架构分析;通过正向追溯,可以迅速定位缺陷对应的代码执行逻辑,帮助开发人员快速修复缺陷,可追踪难复现缺陷。

相反,在测试监控分析平台的帮助下,可以实现程序代码到测试用例的反向追溯。下图就是反射追溯的一个过程展示。

图片

通过反向追溯,我们很容易就能确定代码块对应的测试集,获取到的增量代码,通过智能用例选取算法,可以准确的确定需要回归的测试用例。精准的确定回归测试范围,避免了全量回归造成测试资源的浪费,既保证了质量又缩短了版本的迭代周期。

代码覆盖

有了精准测试,覆盖率统计不再是白盒测试的技术专利。使用精准测试技术,系统测试也可以实现程序的覆盖率分析,而且可以不需要源代码,实现运行代码的指令覆盖、分支覆盖、圈复杂度、行覆盖和方法覆盖的统计分析。

图片

程序代码的覆盖率统计可以是单次执行的数据,也可以是多次执行的累计数据,获得一段时间内或多人测试执行的累计效果,支持在软件研发周期内整体评估测试的覆盖程度。

传统的黑盒测试技术属于经验型模糊测试,质量、进度不可视,产生的无效劳动较多,系统与人员的管理成本极高,软件质量风险高。

图片

传统的黑盒测试大约70%的缺陷很容易发现,但之后缺陷的发现效率会急剧的下降。而传统的白盒测试技术直接面对代码测试,难度大、效率低,仅关注覆盖率,无系统性。精准测试是采用传统黑盒测试与白盒测试相结合的模式,它可以在黑盒测试过程中,通过专用软件自动采集白盒级别的运行逻辑数据,根据可视化出来的不足点和漏洞点,引导开发和测试有针对性的补充测试用例,提高缺陷发现效率。

2、精准测试建设要用到的三个关键技术

  • 差异化

  • 调用链

  • 覆盖率

接下来一个个详细来说~

2.1 差异化分析

差异化其实大家平常接触的挺多的,例如在提交代码的时候,git就会告诉你代码的差异在哪里
而今天要介绍的并不是它,而是叫AST(abstract syntax tree)即抽象语法树,是源代码的抽象语法结构的树状表现形式,每一个节点代表一个语法结构。

不同的语言,都会有对应不同的语法分析器,语法分析器会把源代码作为字符串读入、解析,并建立语法树,这是一个程序完成编译所必要的前期工作。

我们看下 Java 的编译过程,重点关注步骤一和步骤二:

图片

这里我们使用一个简单的Java对象,解析成AST后看下长什么样子

图片

在实际的使用中,可以利用JavaParser来生成并操作AST,会更加方便。

大概的流程逻辑如下

图片

2.2 调用链分析

2.2.1 字节码

说到了调用链,就不得不提字节码,这里先来简单了解下关于Java字节码的信息。

因为Java代码的运行,是通过javac先将Java文件编译成.class结尾的字节码,再由JVM去执行;所以在字节码文件中,拥有了足够的元数据来解析类中的所有元素:类名称、父类名、方法、属性以及 Java 字节码(指令);

图片

通过字节码可以看到Java运行所需的所有信息,且JVM对于字节码文件要求严格,必须按照固定的组成和顺序,而这种特性也就适合利用访问者模式对字节码文件进行修改;因此也就要介绍我们的调用链生成的核心技术栈——ASM

2.2.2 ASM

对于字节码的操作,这里选用的是ASM框架,ASM是一个字节码操纵框架,可以对字节码进行CRUD操作;

ASM API基于访问者模式,为我们提供了ClassVisitorMethodVisitorFieldVisitor API接口,每当ASM扫描到类字段是会回调visitField方法,扫描到类方法是会回调MethodVisitor,扫描到类注解就会回调AnnotationVisitor等;

而方法体内的信息我们就可以通过MethodVisitor提供的visitXXXXInsn()方法来实现字节码的读取和插入,例如在做调用链分析时我们就用到了其visitMethodInsn方法来对方法体内的调用信息进行过滤和提取

通过上述的信息进行匹配桥接,我们就可以拿到调用链中的一系列父子节点,形成我们的方法调用链。

当然,这里我们也是需要一些降噪处理的,排除链路中的get/set、二方包、三方包、toString、init等业务分析无关的方法,使调用链链路聚焦于核心业务,不然会复杂的像个无止尽的蜘蛛网,实用性大打折扣~

大概的流程逻辑如下:

图片

2.3 覆盖率统计

说到覆盖率统计,就要介绍当前在这个技术领域中占据主导地位的开源工具-jacoco

jacoco使用总的来说和装大象一样,需要三步

  • 1. 对被测项目进行字节码插桩

  • 2. 覆盖率数据的采集与导出

  • 3. 覆盖率数据的统计与报告生成

下面我们对这三个步骤逐一拆解

2.3.1 字节码插桩

jacoco的插桩其实使用的也是字节码技术,可见字节码技术的强大之处

插桩,其实就是安插监控探头,我们的一行行代码就好比一条条马路,代码里的分支(if-else)就好比马路上的各种支路岔道,而插桩就相当于在每一条路的路口都装上了一个探头

如下就是在字节码中插入探针信息的图示:

图片

jacoco的插桩模式有两种:

  • on-the-fly模式(运行时插桩)

    • 通过配置-javaagent在启动命令中,jacoco介入被测项目部署过程,将探针(探头)插入class文件,探针不改变原有方法的行为,只是记录是否已经执行。

    • 优点:无需提前进行字节码插桩,无需考虑classpath 的设置。

    • 缺点:要修改JVM参数,对环境的要求比较高,于一些无法修改启动命令的场景不适用。

  • offline模式(编译时插桩)

    • 在测试之前先对文件进行插桩,生成插过桩的class或jar包,测试插过桩的class和jar包,生成覆盖率信息到文件,最后统一处理,生成报告。

    • 优点:屏蔽工具对虚拟机环境的依赖;

    • 缺点:需要提前侵入代码;无法实时获取覆盖率,只能测试完成后停止项目后统一生成报告

选择:

考虑到我们公司实际的使用场景,需要实时统计覆盖率,并且On-the-fly方式无须入侵应用启动脚本,再加上公司的运维和开发可以配合部署JavaAgent以及jvm启动参数,因此我们最终选择On-the-fly模式进行插桩

图片

2.3.2 覆盖率收集与导出

看了上面的插桩原理,想必覆盖率的收集也就很好理解了,依然是以监控探头为例,当我们测试一行行代码时,就相当于开着车跑在一条条道路上,而每进入一行代码就像是开车进入了一条道路,那么进入的时候就会被监控探头拍摄记录下来,也就知道你跑过哪条路了。

同理,覆盖到一行代码时,探针就会记录下信息,最终也就知道了哪一行代码被覆盖到了

2.3.3 覆盖率数据的统计与报告生成

jacoco统计覆盖率,依然使用的字节码技术,也是使用了ASM

通过对exec文件的解析,jacoco便可以获取所有方法的探针信息,从而计算覆盖率,并对代码进行染色输出报告:

图片

针对代码的染色如下

图片

  • 红色:代表未覆盖

  • 黄色:代表部分覆盖,

  • 绿色:代表完全覆盖

在实际的使用场景中,我们可能还更关注本次修改的代码,测试的时候我们会重点测试本轮开发的新增和改动范围,因此jacoco原生的功能就不能满足了,jacoco原生统计的是全量的覆盖率。

对于改动点,我们称之为增量,可以对jacoco的源码进行了二次开发,使其支持增量的覆盖率统计,以满足日常测试需求;对比上面全量的范围,可以看到增量的统计范围就明确了,数量就少了很多:

图片

  • 大概的架构逻辑如下:

图片

目前,上述所完成的都是对于单应用分析与统计,现如今软件的架构越来越复杂,伴随着微服务的盛行,应用服务之间的相互影响也是越来越大,因此跨应用间的调用链路也是我们需要关注的重点

动态调用链:

开发修改了一个方法或者一个接口,那么这个接口可能被N个应用去调用,一旦这个接口有问题,那么影响面是相当大的;或者这个接口本身没问题,但是上下游没有兼容好,调用出了问题也是影响产品质量的;所以这个也是我们测试关注的重点。

再者,我们日常的测试有很大一部分比例是接口测试,包括自动化也是,接口自动化用例很多。那么如果可以通过调用链路找到本次修改所影响到的最上层的入口接口(HTTPdubbo等),那么通过接口与用例的关联关系,就可以推荐出本轮修改必须要执行的用例,提高用例的精准程度和更加明确的测试范围。

还有,如果改动的接口没有关联的用例,或者用例执行完以后覆盖率不达标,那么也可以对用例进行查漏,添加新的用例进行覆盖。

跨应用的调用链分析,方案有很多,比如基于skywalking进行二次开发,通过插桩监控的方式来获取应用间调用关系,最终和单应用的链路组成完成链路。

对于覆盖率常见问题答疑

关于精准化测试,这里有几个问题会困扰测试开发人员。这里给出一些建议,希望可以对读者有所益处。

1、如果我的代码覆盖率达到100%了,是不是就可以说测试覆盖完全了,质量有保障了?

答:不是, 覆盖率低,质量一定没有保障,但是覆盖率高,只是保障的一个维度达到了。

这里我们只是知道了代码被覆盖了,但是代码逻辑的正确性呢?精准化是无法判断的,要靠大家自己去断言了。

再者,覆盖到的代码都是开发按照自己理解的业务逻辑写的,如果他漏写了一些需求逻辑呢?那这部分就不存在覆盖的情况了。

2、我是不是每次都要保证所有的方法覆盖率都达到100%?

答:不是,方法的覆盖率要达到什么样的一个值,不好直接下结论。有些代码逻辑,好比一些异常的捕获,这个异常的触发场景很难,日常测试几乎走不到,那么就是覆盖不了,覆盖率也就不可能达到100%。

3、根据问题2,既然达不到100%,那么我是不是设一个阈值,好比80%?90%?,达到这个阈值就可以了?

答:也不是,有些方法,它的代码逻辑可能都是核心逻辑,其中的分支都需要覆盖,缺少了就有漏测出Bug的风险,且理论上都是可以通过测试覆盖到的,那么这种方法就需要达到100%的覆盖率。

4、那要怎么衡量覆盖率的指标?

答:一方面可以设定一个最低阈值,哪怕代码有些逻辑走不到,也不会大面积并且占比很高,还是需要一个最低的覆盖率保障;

再者,需要测试的同学根据自己测试的业务进行情况划分,具备codereview的能力和习惯,平台仅作为一个辅助测试的工具;

最后,我们可以记录下以往测试的覆盖率,根据不同业务通过测试后的覆盖率情况统计覆盖率的趋势,以历史的覆盖率数据为依据来设定阈值或监控告警,如果覆盖率低于往期正常的值,就进行告警或者卡点。

软件技术-自动化测试技术25

软件技术-自动化测试技术 · 目录

上一篇自动化测试技术13:Appium在移动APP自动化测试的应用下一篇自动化测试技术16:试试流量回放技术,不用人工写自动化测试脚本了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值