软件测试中的变异测试——变异得分和分析示例
变异测试
变异测试是另一种软件测试形式,它通过更改或变异源代码中的语句来确定测试用例是否能够检测源代码中的错误。它用于确保测试用例的质量,特别是其鲁棒性,即它必须使变异后的源代码失效。
变异测试不仅用于确定现有软件测试的质量,还用于设计新的软件测试。在变异测试中,程序会以细微的方式进行修改。它强调帮助测试人员开发有效的测试并检测程序测试数据中的瓶颈。
1971年,Richard Lipton 首次提出变异测试。最初由于其高成本,变异测试并未得到广泛应用。然而,如今它已广泛应用于 Java 和 XML 等多种语言。它是一种白盒测试,可以应用于设计模型、规范、数据库、测试甚至 XML。变异测试是一种典型的结构化测试技术,它利用代码的结构来指导测试。可以将其视为以细微的方式重写源代码以避免冗余的过程。
测试人员需要注意的一点是,要使源代码的更改极其细微,以免影响程序的主要目的。它也被称为基于错误的测试策略,因为它涉及一个有缺陷的程序,主要用于单元测试。
变异测试的类型
值变异 - 在这种测试中,修改值以查找程序中的错误。一个较小的值被修改为较大的值,反之亦然。通常,在值变异测试中会更改常量。
决策变异 - 在这种测试中,修改逻辑/算术运算符以发现程序中的错误。
语句变异 - 在这种测试中,删除语句或将其替换为另一个语句。
变异测试的过程
通过引入许多称为变体的版本,在源代码中创建错误。一个变体只能有一个错误。目的是使这些变体版本失效,从而显示测试用例的有效性。
然后,将测试用例应用于实际程序和变异程序。测试用例必须适当,并进行调整以查找程序中的错误。
比较从实际程序获得的结果与变异程序的结果。
如果实际程序和变异程序产生不同的输出,则测试用例会破坏变体。因此,测试用例足以找到两个程序(实际程序和变异程序)之间的差异。
创建变异程序
变异是在程序语句中进行的单个语法修改。每个这样的变异程序都必须与实际程序恰好只有一个变异不同。例如:
实际程序 | 变异程序 |
---|---|
if (x > y) | if (x < y) |
print “Hello readers.” | print “Hello readers.” |
else | else |
print “How you doing?” | print “How you doing?” |
对变异程序进行的更改
有很多技术可以生成变异程序,例如:
操作数替换运算符 | 表达式修改运算符 | 语句修改运算符 |
---|---|---|
操作数被替换为另一个操作数或常数值。 | 在程序语句中替换运算符或插入新的运算符。 | 更改程序语句以创建变异程序。 |
例如,如果 (a > b) 替换 a 和 b 值,如果 (5 > b) 将 a 替换为 5 | 例如,如果 (a == b) 将 == 替换为 >= 并将变异程序设为 if (a >= b),并在语句中添加 ++ if (x == ++y) | 例如,删除 if-else 语句中的 else 语句。删除整个 if-else 语句以确定程序的行为。示例变异运算符
|
自动化变异测试
变异测试非常耗时,而且手动执行起来也很复杂。因此,建议使用自动化工具和技术来加快测试过程。这些工具还可以减少测试过程的支出。一些用于变异测试的自动化工具包括:
Stryker - 这个开源工具有助于对 .NET Core 和 .NET Framework 项目进行变异测试。它可以通过临时在源代码中引入错误来测试测试用例。它可以控制超过 30 种受支持的变异。Stryker 通过使用代码分析和并行测试运行器进程来加快测试速度。此工具支持 JavaScript、TypeScript、C# 和 Scala。Stryker 使用智能且功能强大的报告来发现幸存的变异体并提高测试效率。
PIT 测试 - PIT(流程集成测试)工具有助于为流程集成场景设置自动化测试。此工具背后的理念是:从 SAP 流程集成或 SAP 流程编排系统的运行时检索处理的消息。这些消息存储在 PIT 系统的数据库中,稍后可以在不同的系统(称为目标系统)上运行。运行这些消息后,从目标系统收集结果。然后,将结果与来自源的参考消息进行比较。此工具是变异测试领域的最新技术,为 JAVA 和 JVM 提供标准的测试覆盖率。此工具快速、强大且易于与现代测试和构建工具集成。PIT 测试易于使用,积极开发和支持。它以易于阅读和理解的格式生成报告,集成行覆盖率和变异覆盖率信息。
变异测试的概念
变体 - 它是源代码的变异或修改版本,其中包含细微的更改。当测试数据通过变体执行时,它会产生与原始源代码不同的结果。它们也称为变异程序。
幸存变体 - 这些是在测试数据通过源代码的原始版本和变异版本执行后仍然存在的变体。必须销毁幸存的变体,它们也称为活动变体。
被杀死的变体 - 这些变体在变异测试完成后被销毁。这些是通过原始和变异源代码的不同结果获得的。
等效变体 - 这些变体与活动变体密切相关,即即使在测试数据通过它们运行后它们仍然存在。它们与其他变体不同,因为它们与原始源代码具有相同的含义,而不管它们可能不同的上下文如何。
变异得分 - 变异得分是用销毁的变体数量除以变体的总数,然后乘以 100 得到的百分比:
变异得分 = (销毁的变体数 / 变体的总数) * 100
如果变异得分为 100%,则测试用例被认为是变异充分的。研究和实验表明,变异技术是衡量测试用例充分性或适当性的有效方法。然而,变异测试的主要缺点是创建变体和针对该变异程序执行测试用例所涉及的高成本。
变异测试的优点
获得高源程序覆盖率的强大方法。
能够全面测试变异程序。
良好的错误检测水平。
检测源代码中的冗余和歧义,能够检测程序中的所有错误。
提供最可靠和稳定的系统。
变异测试的缺点
由于必须生成大量变异程序,因此极其昂贵且耗时。
由于其高度复杂性,变异测试必须使用自动化工具。
每个变异都与原始程序具有相同数量的测试用例;因此,必须使用实际测试套件测试大量变异程序。
它涉及源代码更改,因此不能应用于黑盒测试。
变异测试示例
考虑一个允许用户注册的医院网站。它收集各种信息,例如出生日期或年龄等。如果患者年龄大于15岁,则会为他们分配一位医生作为他们的主治医生。为此,它启用了“医生”功能,该功能查找可用的医生。可能还有一些其他功能。10岁以下的患者可能会被分配给儿科医生,等等。但我们只考虑年龄大于15岁的情况。代码可能如下所示:
读取年龄。
如果 (年龄>15)
医生 = 医生()
结束 if。
请注意,代码特定于任何语言,因此无法运行。它只是一个伪代码。
我们的目标是检查4个值(14、15、0和5)的数据集是否足以发现此代码中的所有问题和冗余。
那么,变异测试是如何实现的呢?首先,创建变体——程序的变体。变体只是一个程序,写成一个偏差。它带有自播种问题,例如,算术运算符替换、逻辑连接符替换、语句删除等。这些替换被称为变异算子。
结论
执行详尽测试的最佳方法是通过变异测试——测试任何程序最全面的方法。此技术检查程序的有效性和准确性,以检测系统中的故障或错误。