为什么jacococoverage报告中说如果(a&&b&&c)实际上是6个分支?

6mw9ycah  于 2021-07-12  发布在  Java
关注(0)|答案(3)|浏览(434)

我的公司有一个要求,我们达到90%的测试覆盖率的新代码,而对于java代码,我使用gradle jacoco插件,这是很好的;然而,当分支数开始指数增长时(夸张地说,这可能是几何增长),分支覆盖率很难提高到90%。
下面是一个非常做作的例子:

public class Application {
    public static void test(boolean a, boolean b) {
        if (a && b) {
            System.out.println("true!");
        } else {
            System.out.println("false!");
        }
    }
}

以及测试:

public class ApplicationTests {
    @Test
    public void test() {
        Application.test(true, true);
        Application.test(false, false);
    }
}

以下是报道内容:

它还说,我错过了4个分支中的1个,或者换句话说,我覆盖了4个分支中的3个(75%的分支覆盖率)。
如果我在这里增加布尔数,分支数似乎是n*2,其中n是布尔数。所以3(a,b,c)变成6个分支,10变成20个分支。所以我想我不明白在这种情况下有6到20个分支意味着什么。
为了回答这个问题-我可以
a) 将jacoco配置为更直观,并将if/else条件视为始终具有2个分支(分支1是if执行时的分支,分支2是else执行时的分支)--子表达式的延迟执行可以作为行覆盖率或其他内容进行跟踪。
b) 为了更全面地解释为什么它说有4,6,20个分支,这些if/else有2,3,10个布尔值组合成1个表达式。
编辑——澄清混淆的来源:
在本例中,当只有2个调用时,如何覆盖3个分支?
为什么3个布尔的分支数 (a && b && c) 在本例中,转到6个分支和10个布尔 (a && b && c && .. && j) 去20家分店?
如果每个布尔值不是真就是假,然后我用这两种状态调用函数,我怎么没有得到100%的分支覆盖率呢?我错过了一些东西。

o7jaxewo

o7jaxewo1#

当您编写if(a&&b)这样的条件时,在运行测试用例时,它将与下面提到的所有四个场景一起运行。

result a     b
true   true  true
false  false true
false  true  false
false  false false

所以你需要调用这个方法四次 100% coverage .
您还可以创建一些实用程序类,根据参数的数量生成这些场景。

a9wyjsp7

a9wyjsp72#

我想我现在已经明白了为什么分支数等于n*2,其中n是if()条件中布尔表达式的个数。
每个布尔表达式都是自己的分支,因此在本例中,如果 a && b && c 有3个不同的表达式,每个表达式有2个状态和6个分支。为了覆盖所有6个分支,测试必须确保每个变量都在true和false状态下进行评估。关键的一点是每个表达式都必须求值,在某些情况下,由于java中的延迟求值,它们不会被求值。

public class Application {
    public static void test(boolean a, boolean b, boolean c) {
        if (a && b && c) {
            System.out.println("true!");
        } else {
            System.out.println("false!");
        }
    }
}

举个例子 if (a && b && c) 路过时 a , b ,和 c 重视所有 true ,这实际上在一次执行中覆盖了3个分支。但是如果你通过了所有的考试 false ,它只覆盖一个分支,因为 b 以及 c 从不检查,因为 a 错误和懒惰的评价。
在这种情况下,为了有效地覆盖所有6个分支,必须至少调用测试函数4次,以实现100%的分支覆盖率。

/*
 * Using ? to indicate it can be true or false,
 * it won't matter because the variable would never be read due to lazy evaluation.
 */
Application.test(true, true, true);  // +3 branches covered
Application.test(true, true, false); // +1 branch covered
Application.test(true, false, ?);    // +1 branch covered
Application.test(false, ?, ?);       // +1 branch covered
                                     // total: 6 branches
4jb9z9bj

4jb9z9bj3#

在本例中,您实际上只需要3个测试就可以获得100%的覆盖率。当这两个都是假的时候测试这个案例并不能提供任何额外的覆盖范围。凭直觉,这应该是有道理的。除非至少有一个参数为false,否则您希望它打印为true。
构造代码的方式也会影响分支的数量。如果要求做一件事,那么当所有这些都是真的,而当其中任何一个都是假的,那么你可以用两个分支来做:

if (Stream.of(a,b).reduce(Boolean::logicalAnd).get(){
   System.out.println("true");
} else {
   System.out.println("false");
}

在一个只有两个输入的人为例子中,它看起来有点愚蠢。如果在一个实际的上下文中有两个以上的输入,那么就更有意义了。例如,你可以有一个 List<ValidationRule> 每个元素计算一个布尔值。我不想多说,因为这超出了你最初的问题范围,但这可能是值得考虑的问题。

相关问题