Pitest 以看似不可能的方式改变 Java 源代码
Pitest mutates Java source code in ways that seem not possible
我写了一个简单的程序,给定三个代表三角形边长的整数,输出它是哪种类型的三角形。
然后我写了一组测试用例和 运行 使用 pitest 的突变覆盖率。
我的目标是获得 100% 的突变覆盖率,我认为这是可行的,因为它是一个非常简单的程序。
我的问题是 pitest 引入了我不理解的突变,因此不知道如何杀死。
程序如下:
public class TriangleType {
public String triangleType(int ab, int ac, int bc) {
if(ab <= 0 || ac <= 0 || bc <= 0) {
return "sign fail";
}
if(ab + ac <= bc || ab + bc <= ac || ac + bc <= ab) {
return "triangle inequality fail";
}
if(ab == ac && ab == bc) {
return "equilateral";
}
if(ab == ac || ab == bc || ac == bc) {
return "isoceles";
}
return "scalene";
}
}
这里是测试用例:
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
class TriangleTypeTestMutation extends TriangleTypeTest{
protected TriangleType triangleType;
@BeforeEach
void setUp() {
triangleType = new TriangleType();
}
@Test
void testEquilateral() {
assertEquals("equilateral", triangleType.triangleType(1,1,1));
assertEquals("equilateral", triangleType.triangleType(7, 7, 7));
}
@Test
void testIsoceles() {
assertEquals("isoceles", triangleType.triangleType(5, 5, 2));
assertEquals("isoceles", triangleType.triangleType(2, 5, 5));
assertEquals("isoceles", triangleType.triangleType(5, 2, 5));
}
@Test
void testScalene() {
assertEquals("scalene", triangleType.triangleType(3, 5, 7));
assertEquals("scalene", triangleType.triangleType(10, 4, 7));
}
@Test
void testTriangleInequalityFail() {
//Should not answer scalene
assertEquals("triangle inequality fail", triangleType.triangleType(100, 3, 4));
assertEquals("triangle inequality fail", triangleType.triangleType(2, 50, 3));
assertEquals("triangle inequality fail", triangleType.triangleType(1, 2, 33));
//Should not answer isoceles
assertEquals("triangle inequality fail", triangleType.triangleType(100, 3, 3));
assertEquals("triangle inequality fail", triangleType.triangleType(2, 50, 2));
assertEquals("triangle inequality fail", triangleType.triangleType(1, 1, 33));
}
@Test
public void testKillConditionalBoundaryMutation() {
assertEquals("sign fail", triangleType.triangleType(0, 1, 2));
assertEquals("sign fail", triangleType.triangleType(1, 0, 2));
assertEquals("sign fail", triangleType.triangleType(1, 1, 0));
assertEquals("triangle inequality fail", triangleType.triangleType(1, 1, 2));
assertEquals("triangle inequality fail", triangleType.triangleType(2, 1, 1));
assertEquals("triangle inequality fail", triangleType.triangleType(1, 2, 1));
}
@Test
public void testKillLessOrEqualToEqual() {
assertEquals("sign fail", triangleType.triangleType(-1, 1, 5));
assertEquals("sign fail", triangleType.triangleType(1, -1, 5));
assertEquals("sign fail", triangleType.triangleType(1, 1, -5));
}
}
下面是一些我不明白的突变:
例如关于行 if(ab == ac && ab == bc){ return "equilateral";}
- 不等于大于 -> SURVIVED
- 递增 (a++) 整数局部变量编号 3 -> SURVIVED
如果我的代码中没有不等于,它怎么会变成不等于大于?
另外,我没有局部变量。它是否将方法的参数视为局部变量?
Pitest 改变字节码而不是源代码。修改器试图描述源文件中的等效更改,但有时这并不简单。
这些突变看起来是由 'rv' 突变体产生的。这些通常比标准集质量低,不推荐用于一般用途。除非有特殊原因,否则不要使用它们。
“增加局部变量”应该真正读作“增加局部变量或参数”。运营商需要进行额外的分析才能确定。
不等于大于改变将改变字节码中的 IFNE 指令。在最简单的情况下,这将映射到 != 检查,如突变描述所建议的那样,但编译器可能会在生成其他逻辑结构时选择使用此指令(在这种情况下,等式检查与 && 相结合)。该描述肯定具有误导性,更新突变器以使其更准确将涉及编写反编译器的大部分内容。
我写了一个简单的程序,给定三个代表三角形边长的整数,输出它是哪种类型的三角形。 然后我写了一组测试用例和 运行 使用 pitest 的突变覆盖率。
我的目标是获得 100% 的突变覆盖率,我认为这是可行的,因为它是一个非常简单的程序。
我的问题是 pitest 引入了我不理解的突变,因此不知道如何杀死。
程序如下:
public class TriangleType {
public String triangleType(int ab, int ac, int bc) {
if(ab <= 0 || ac <= 0 || bc <= 0) {
return "sign fail";
}
if(ab + ac <= bc || ab + bc <= ac || ac + bc <= ab) {
return "triangle inequality fail";
}
if(ab == ac && ab == bc) {
return "equilateral";
}
if(ab == ac || ab == bc || ac == bc) {
return "isoceles";
}
return "scalene";
}
}
这里是测试用例:
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
class TriangleTypeTestMutation extends TriangleTypeTest{
protected TriangleType triangleType;
@BeforeEach
void setUp() {
triangleType = new TriangleType();
}
@Test
void testEquilateral() {
assertEquals("equilateral", triangleType.triangleType(1,1,1));
assertEquals("equilateral", triangleType.triangleType(7, 7, 7));
}
@Test
void testIsoceles() {
assertEquals("isoceles", triangleType.triangleType(5, 5, 2));
assertEquals("isoceles", triangleType.triangleType(2, 5, 5));
assertEquals("isoceles", triangleType.triangleType(5, 2, 5));
}
@Test
void testScalene() {
assertEquals("scalene", triangleType.triangleType(3, 5, 7));
assertEquals("scalene", triangleType.triangleType(10, 4, 7));
}
@Test
void testTriangleInequalityFail() {
//Should not answer scalene
assertEquals("triangle inequality fail", triangleType.triangleType(100, 3, 4));
assertEquals("triangle inequality fail", triangleType.triangleType(2, 50, 3));
assertEquals("triangle inequality fail", triangleType.triangleType(1, 2, 33));
//Should not answer isoceles
assertEquals("triangle inequality fail", triangleType.triangleType(100, 3, 3));
assertEquals("triangle inequality fail", triangleType.triangleType(2, 50, 2));
assertEquals("triangle inequality fail", triangleType.triangleType(1, 1, 33));
}
@Test
public void testKillConditionalBoundaryMutation() {
assertEquals("sign fail", triangleType.triangleType(0, 1, 2));
assertEquals("sign fail", triangleType.triangleType(1, 0, 2));
assertEquals("sign fail", triangleType.triangleType(1, 1, 0));
assertEquals("triangle inequality fail", triangleType.triangleType(1, 1, 2));
assertEquals("triangle inequality fail", triangleType.triangleType(2, 1, 1));
assertEquals("triangle inequality fail", triangleType.triangleType(1, 2, 1));
}
@Test
public void testKillLessOrEqualToEqual() {
assertEquals("sign fail", triangleType.triangleType(-1, 1, 5));
assertEquals("sign fail", triangleType.triangleType(1, -1, 5));
assertEquals("sign fail", triangleType.triangleType(1, 1, -5));
}
}
下面是一些我不明白的突变:
例如关于行 if(ab == ac && ab == bc){ return "equilateral";}
- 不等于大于 -> SURVIVED
- 递增 (a++) 整数局部变量编号 3 -> SURVIVED
如果我的代码中没有不等于,它怎么会变成不等于大于?
另外,我没有局部变量。它是否将方法的参数视为局部变量?
Pitest 改变字节码而不是源代码。修改器试图描述源文件中的等效更改,但有时这并不简单。
这些突变看起来是由 'rv' 突变体产生的。这些通常比标准集质量低,不推荐用于一般用途。除非有特殊原因,否则不要使用它们。
“增加局部变量”应该真正读作“增加局部变量或参数”。运营商需要进行额外的分析才能确定。
不等于大于改变将改变字节码中的 IFNE 指令。在最简单的情况下,这将映射到 != 检查,如突变描述所建议的那样,但编译器可能会在生成其他逻辑结构时选择使用此指令(在这种情况下,等式检查与 && 相结合)。该描述肯定具有误导性,更新突变器以使其更准确将涉及编写反编译器的大部分内容。