17

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

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

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

断言真:

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

断言真:

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

断言空:

assertNull( myObject ) //complete;
4

3 回答 3

21

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

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

为了计算这个值,Java 编译器生成将两个参数压入堆栈的代码,然后执行条件跳转以将 1(真)或 0(假)压入堆栈。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 的精彩和批判性讨论。

于 2012-04-13T20:29:15.337 回答
0

Emma 将条件表达式视为(分支)覆盖率计数恕我直言的“带有分支的东西”这一事实似乎完全被打破了。它不是条件分支。

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

我们的Java 测试覆盖率工具对此类条件“正确”进行(分支)覆盖率分析。

于 2012-04-14T14:58:51.220 回答
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);

    }
于 2014-10-04T00:20:06.870 回答