在Python中使用 Mutpy 模块进行变异测试
先决条件:突变测试
Mutpy是Python中的突变测试工具,可生成突变体并计算突变分数。它支持标准的 unittest 模块,生成 YAML/HTML 报告并具有彩色输出。它在 AST 级别上应用突变。
安装:
这个模块没有内置在Python中。要安装它,请在终端中键入以下命令。
pip install mutpy
在这里,我们将使用 Mutpy 库来执行为一个简单程序编写的测试用例。
现在,我们对一个检查数字是否为素数的程序执行突变测试。
代码:此代码另存为isPrime.py
Python3
# define a function
def isPrime(num):
if num > 1:
# check for factors
for i in range(2,num):
if (num % i) == 0:
return False
else:
return True
# if input number is less than
# or equal to 1, it is not prime
else:
return False;
Python3
# import required libraries
from unittest import TestCase
from isPrime import isPrime
# define a class
class CalculatorTest(TestCase):
# test case for checking non prime nums
def test_nonprime(self):
self.assertEqual(isPrime(12),False)
# test case to check prime nums
def test_prime(self):
self.assertEqual(isPrime(19),True)
# test case to check invalid input
def test_invalid(self):
self.assertEqual(isPrime(-1),False)
现在,我们需要使用Pytest或Unittest库为上述程序编写测试用例。测试用例应该使用杀死所有突变体的方法来编写,即测试用例应该足够有效以给出良好的突变分数。测试用例是使用如下所示文件中的Unittest库编写的。
测试用例是使用self.assertEqual()编写的,它是一个测试断言,通常用于确定测试用例是通过还是失败。我们在下面编写了三个测试函数来检查三种类型的输入:
- 输入是素数
- 输入非素数
- 输入无效
注意:函数名和测试文件名应始终以单词“test”开头。
代码:此代码另存为 test_isPrime.py。
Python3
# import required libraries
from unittest import TestCase
from isPrime import isPrime
# define a class
class CalculatorTest(TestCase):
# test case for checking non prime nums
def test_nonprime(self):
self.assertEqual(isPrime(12),False)
# test case to check prime nums
def test_prime(self):
self.assertEqual(isPrime(19),True)
# test case to check invalid input
def test_invalid(self):
self.assertEqual(isPrime(-1),False)
要执行这些测试用例,我们需要在一个文件夹中创建两个单独的文件isPrime.py和test_isPrime.py并在命令提示符下运行以下命令:
mut.py --target isPrime --unit-test test_isPrime -m --runner pytest
在上面的命令中,我们必须指定三件事:
- 目标:将运行测试用例的目标文件,在我们的例子中是isPrime.py
- 单元测试:包含必须执行的单元测试的文件,即我们的例子中的test_isPrime.py 。
- 亚军: pytest 或 unittest
输出将是一组突变体以及突变分数、被杀死的突变数、幸存的突变数等细节。
[*] Start mutation process:
- targets: isPrime
- tests: test_isPrime
[*] 3 tests passed:
- test_isPrime [3.07469 s]
[*] Start mutants generation and execution:
- [# 1] AOR isPrime:
--------------------------------------------------------------------------------
3:
4: if num > 1:
5:
6: for i in range(2, num):
- 7: if num % i == 0:
+ 7: if num * i == 0:
8: return False
9: else:
10:
11: return True
--------------------------------------------------------------------------------
[1.45151 s] killed by testing program mutpy/test_isPrime.py::CalculatorTest::test_nonprime
- [# 2] COI isPrime:
--------------------------------------------------------------------------------
1:
2: def isPrime(num):
3:
- 4: if num > 1:
+ 4: if not (num > 1):
5:
6: for i in range(2, num):
7: if num % i == 0:
8: return False
--------------------------------------------------------------------------------
[1.25723 s] killed by testing program mutpy/test_isPrime.py::CalculatorTest::test_invalid
- [# 3] COI isPrime:
--------------------------------------------------------------------------------
3:
4: if num > 1:
5:
6: for i in range(2, num):
- 7: if num % i == 0:
+ 7: if not (num % i == 0):
8: return False
9: else:
10:
11: return True
--------------------------------------------------------------------------------
[1.28817 s] killed by testing program mutpy/test_isPrime.py::CalculatorTest::test_prime
- [# 4] CRP isPrime:
--------------------------------------------------------------------------------
1:
2: def isPrime(num):
3:
- 4: if num > 1:
+ 4: if num > 2:
5:
6: for i in range(2, num):
7: if num % i == 0:
8: return False
--------------------------------------------------------------------------------
[1.23510 s] survived
- [# 5] CRP isPrime:
--------------------------------------------------------------------------------
2: def isPrime(num):
3:
4: if num > 1:
5:
- 6: for i in range(2, num):
+ 6: for i in range(3, num):
7: if num % i == 0:
8: return False
9: else:
10:
--------------------------------------------------------------------------------
[1.20360 s] survived
- [# 6] CRP isPrime:
--------------------------------------------------------------------------------
3:
4: if num > 1:
5:
6: for i in range(2, num):
- 7: if num % i == 0:
+ 7: if num % i == 1:
8: return False
9: else:
10:
11: return True
--------------------------------------------------------------------------------
[1.23499 s] killed by testing program mutpy/test_isPrime.py::CalculatorTest::test_prime
- [# 7] ROR isPrime:
--------------------------------------------------------------------------------
1:
2: def isPrime(num):
3:
- 4: if num > 1:
+ 4: if num < 1:
5:
6: for i in range(2, num):
7: if num % i == 0:
8: return False
--------------------------------------------------------------------------------
[1.24164 s] killed by testing program mutpy/test_isPrime.py::CalculatorTest::test_invalid
- [# 8] ROR isPrime:
--------------------------------------------------------------------------------
1:
2: def isPrime(num):
3:
- 4: if num > 1:
+ 4: if num >= 1:
5:
6: for i in range(2, num):
7: if num % i == 0:
8: return False
--------------------------------------------------------------------------------
[1.21934 s] survived
- [# 9] ROR isPrime:
--------------------------------------------------------------------------------
3:
4: if num > 1:
5:
6: for i in range(2, num):
- 7: if num % i == 0:
+ 7: if num % i != 0:
8: return False
9: else:
10:
11: return True
--------------------------------------------------------------------------------
[1.32597 s] killed by testing program mutpy/test_isPrime.py::CalculatorTest::test_prime
[*] Mutation score [14.91747 s]: 66.7%
- all: 9
- killed: 6 (66.7%)
- survived: 3 (33.3%)
- incompetent: 0 (0.0%)
- timeout: 0 (
我们可以从上面的输出中看到,6 个突变体被杀死,只有 3 个突变体能够存活。此外,获得了 66.7% 的突变分数。我们可以通过分析在测试用例中幸存下来的突变体并编写新的或修改的测试用例来杀死幸存的突变体来进一步提高这个突变分数。