【问题标题】:Missing branches when using assertTrue instead of assertNull使用 assertTrue 而不是 assertNull 时缺少分支
【发布时间】:2012-04-13 18:07:25
【问题描述】:

在 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;

【问题讨论】:

  • 使用 assertNull 断言 null 有什么问题?通常最好为被断言的事物使用适当的断言类型。您最好在测试失败时查看问题所在,而无需过多地研究测试代码。
  • @nansen 这是真的,如果需要,我使用 assertNull 没有问题,但是,IMO,所有断言“类型”只是 assertTrue 的另一种形式。使用不同的断言类型可能会带来额外的好处,例如添加错误信息/可读性,但这在这里并不是真正的问题。
  • @nansen 这并不是说我拒绝使用 assertNull 并且可能会使用它,我只是发现这个特殊的问题很有趣,因为我基本上是在测试同样的东西,但艾玛完全给出了不同的结果。
  • 为什么要在测试代码上运行代码覆盖?我认为没有人应该关心您的所有测试代码分支是否都经过测试。这看起来很傻。
  • 根本问题与测试代码的运行覆盖率无关,也与使用 assertNull 与 assertTrue 无关。

标签: junit code-coverage bytecode emma jacoco


【解决方案1】:

对于大多数布尔表达式,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 代码的 条件 覆盖率(而不仅仅是 branch 覆盖率)。

此功能没有很好的文档记录,但这里有一些提示:

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

注意:由于最初的答案太过猜测,因此是否进行了重大编辑。感谢@ira-baxter 的精彩和批判性讨论。

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • JUnit API 中的 assertTrue / assertNull 方法没有什么特别之处。如果条件不成立,他们只会抛出 java.lang.AssertionError。这与 Java 的 assert 关键字没有直接关系。
    • 我同意将这个 Emma/JaCoCo 功能称为 分支覆盖 是(非常)令人困惑的。 (单独的)覆盖信息告诉我任何布尔(子)表达式是否评估为真和假是一个有用的功能。
    • @avandeursen:确定程序中的每个 条件 是否已被执行为“真”或“假”不是分支覆盖;这是“条件覆盖”。当然,我们的工具不做条件覆盖;根据过去的理解,我不相信艾玛会提供条件覆盖,但我可能会感到惊讶。
    • 感谢 Ira,你让我思考,我对答案进行了重大编辑。
    【解决方案3】:

    要在布尔方法上获得 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);
    
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-15
      • 1970-01-01
      • 1970-01-01
      • 2014-09-19
      • 2020-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多