Pi测试突变在试图降低时间复杂度时存活



我有一个算法,检查给定字符串列表中哪个字符串与另一个给定字符串最匹配,它是-

String calcMostMatching(String mainStr, List<String> strings) {
String mostMatching = null;
if (strings.size() == 1) {
// if size is 1, return the only present string.
mostMatching = strings.get(0);
} else {
// This algorithm also works for size() == 1 but I don't                       
// want to use it when size() == 1
char[] charArrayOfMainStr = mainStr.toCharArray();
for (String str : strings) {
char[] charArrayOfStr = str.toCharArray();
int min = Math.min(charArrayOfMainStr.length, charArrayOfStr.length)
for (int i = 0; i < min; i++) {
int count = 0;
if (charArrayOfMainStr[i] == charArrayOfStr[i]) {
count++;
} else {
break;
}
}
// Now I store the value of count for 
// each string but let us say a method like str.setCounter(count);
}
// Now I will iterate over the loop to check the mostMatchingString
mostMatching = strings.get(0);
for (int i = 1; i < strings.size(); i++) {
if (mostMatching.getCounter() < strings.get(i).getCounter()) {
mostMatching = strings.get(i);
}
}
}
return mostMatching;
}

现在坑测试失败-

if (strings.size() == 1) {
mostMatching = strings.get(0);
} 

表示用false替换了strings.size() == 1,但仍然通过了所有的测试用例。是的,所有的测试用例都会通过,但是当列表只有一个值时,我想减少时间复杂度。

如果你不知道坑测试,有人能帮我修改这个算法,这样它就不会进入循环当size() == 1除了我所做的。

注意:这不是真正的代码,我把它减少到最小的可重复的例子,实际的代码是不同的,相当复杂,它检查各种参数,而不仅仅是比较getCounter()值。

我怎样才能杀死这个突变,或者我必须忽略它。

性能不是由单位衡量的代码属性在测试中,只为了优化性能而出现的代码将导致无法消除的等效突变。

作为临时练习,您还可以进行最频繁的性能测试,但这将是困难的,因为它们通常给出定量结果,而不是布尔通过/失败。它也会非常慢。

由于您的优化是针对n较低时进行的,因此特别难以衡量可观察到的改进。可能根本就没有实际的改善。除非您的性能测量证明它的存在是合理的,否则最简单的方法是通过删除if语句来降低代码的复杂性。

表示将string .size() == 1替换为false,但仍通过所有测试用例

所以,如果测试失败,那么测试者会很高兴。我建议您增加单元测试的范围,以涵盖执行路径。比如说,如果你有这样的代码-

String calcMostMatching(String mainStr, List<String> strings) {
String mostMatching = null;
if (strings.size() == 1) {
// if size is 1, return the only present string.
mostMatching = strings.get(0);
} else {
// move the complex code to another method
mostMatching = doSomeComplexAlgo(mainStr, strings);
}
return mostMatching;
}
String doSomeComplexAlgo(String mainStr, List<String> strings) {
// do something complex
return strings.get(0);
}

在单元测试中,我们添加了另一个verify方法。它验证doSomeComplexAlgo方法不是用单个字符串列表调用的。现在,如果PiTest测试更改了size,那么测试应该会失败,因为doSomeComplexAlgo将被调用-

@Test
public void testCalcMostMatchingWithSizeOne() {
SomeTestClass someTestClass = Mockito.spy(new SomeTestClass());
String result = someTestClass.calcMostMatching("", List.of("A"));
// This will fail if the mutation testing changes the List length
Mockito.verify(someTestClass, Mockito.times(0)).doSomeComplexAlgo(Mockito.anyString(), Mockito.anyList());
}

最新更新