使用assertTrue而不是assertNull时缺少分支

时间:2012-04-13 18:07:25

标签: junit code-coverage bytecode emma jacoco

在Java / Junit中,我需要使用某个对象测试null。我可以通过多种方式测试条件,但我一直在使用assertTrue进行大多数测试。当我在assertTrue中检查空值时,EclEmma声明它只测试一个分支。

当我手动将语句解析为变量(比如将结果设置为布尔值并将其传递给assertTrue)时,断言的代码覆盖率被认为是完整的,而不是变量初始化行。

为什么会这样?这是否与http://sourceforge.net/apps/trac/eclemma/wiki/FilteringOptions中提到的Java显然添加的额外字节代码有关?任何解决方案(除了使用其他断言语句)。

assertTrue:

assertTrue( myObject == null ); //1 of 2 branches

assertTrue:

boolean test = (myObject == null); //1 of 2 branches missing
assertTrue(test); // complete

assertNull:

assertNull( myObject ) //complete;

3 个答案:

答案 0 :(得分:21)

对于大多数布尔表达式,Java编译器在字节代码中生成额外的分支。 JaCoCo基于生成的字节代码生成“分支覆盖”,而不是基于原始Java代码,因此显示了您将使用的几乎所有布尔表达式的附加分支覆盖率信息。

在您的代码中,您使用的布尔表达式为myObject == null

要计算此值,Java编译器会生成代码,在堆栈上推送两个参数,然后执行条件跳转以便在堆栈上按1(true)或0(false)。 JaCoCo报告该条件跳转的分支覆盖范围。

因此,您使用myObject == null的事实会触发您描述的行为。

作为其他一些例子,试试这个:

boolean t = true;
boolean f = false;
boolean result1 = (t && f) || f; // 3 out of 6 missed.
boolean result2 = !t;            // 1 out of 2 missed.

如果布尔表达式例如由函数返回,则该函数很有用,该函数在其他地方的if-then-else语句中用作条件。虽然主要是Java编译器工作方式的结果,但它有助于评估原始Java代码的条件覆盖范围(而不仅仅是分支覆盖范围)。

这个功能没有太多记录,但这里有一些指示:

实际上,它确实与生成额外字节代码有关,但与过滤选项所针对的合成字节编译器结构的具体示例无关。

注意:自初始回答以来主要编辑是否过于猜测。感谢@ ira-baxter for good&批判性讨论。

答案 1 :(得分:1)

Emma将条件表达式视为“分支”的事物(对于(分支)覆盖计数恕我直言的事实似乎完全被打破了。它不是条件分支。

我们可以更多地讨论断言;如果它被定义为“在断言失败时抛出异常”那么它确实有一个条件分支;如果它被定义[正如我认为的那样,我不是Java专家]因为“在断言失败时终止我的程序”那么它实际上并不是一个分支。方法调用也模糊不清;这些条件分支,因为如果被调用的方法抛出异常,则控制流不会继续到“语句的其余部分”。

我们的Java Test Coverage工具获得了对这些条件“(右)”的(分支)覆盖率分析。

答案 2 :(得分:0)

要获得布尔方法的100%代码覆盖率,请执行以下操作

Class RecordService{


    public boolean doesRecordExist(String id){

    return id!=null;

    }


    }

    //Method inside your mock
    @Test
    public boolean testDoesRecordExist(){
    RecordService recordService = mock(RecordService.class);
    when(recordService.doesRecordExists()).thenReturn(
                    anyString()).thenReturn(null);

    }