SonarQube 问题“向此测试用例添加至少一个断言”,用于具有断言的单元测试?

2022-09-02 21:23:39

我在SonarQube上遇到了问题,在我的几个单元测试中提出了问题,并提示了以下问题:

向此测试用例添加至少一个断言。

每个测试用例都类似于这种格式(其中将许多断言委托给具有常见断言的方法,以避免重复):

@Test
public void companyNameOneTooLong() throws Exception {
    AddressFormBean formBean = getValidBean();
    formBean.setCompanyNameOne("123456789012345678901234567890123456");

    assertViolation(validator.validate(formBean), "companyNameOne", "length must be between 0 and 35");
}

private void assertViolation(Set<ConstraintViolation<AddressFormBean>> violations, String fieldname, String message) {
    assertThat(violations, hasSize(1));
    assertEquals(fieldname, violations.iterator().next().getPropertyPath().iterator().next().getName());
    assertEquals(message, violations.iterator().next().getMessage());
}

现在,显然我可以从私有方法中提取三个断言并将它们放在测试方法中 - 但是我正在多次执行相同的检查(对不同字段)。

所以,我想我会尝试通过(重新)抛出一个:AssertionError

private void assertViolation(Set<ConstraintViolation<AddressFormBean>> violations, String fieldname, String message) throws AssertionError {
    try {
        assertThat(violations, hasSize(1));
        assertEquals(fieldname, violations.iterator().next().getPropertyPath().iterator().next().getName());
        assertEquals(message, violations.iterator().next().getMessage());
    } catch (AssertionError e) {
        throw e;
    }
 }

不幸的是,这种方法也行不通。

JUnit断言方法有什么特别之处/SonarQube专门寻找什么来检查是否为每个测试做出了断言?

或者 - 是否有其他方法可以实现相同的最终结果(避免一遍又一遍地重复共享断言代码)?


答案 1

SonarQube Java Analyzer 中的规则(测试应包括断言)不执行跨过程分析,仅探索被标识为测试方法的方法体(通常用 ) 注释。S2699@Test

因此,如果在执行测试方法时调用的唯一断言是由专用方法完成的(以避免重复),则该规则将引发问题。这是该规则的已知限制,只有当我们能够有效地执行跨过程分析时,我们才会处理它。

关于SonarQube就此类情况提出的问题,您可以安全地将其标记为.Won't Fix

关于检测到的断言,该规则将以下(单元测试)框架中的常用 /// 方法视为断言:assertfailverifyexpect

  • 联合
  • Fest (1.x & 2.x)
  • AssertJ
  • 汉克雷斯特
  • 莫基托
  • 春天
  • 易莫克

答案 2

如果您不希望从测试中引发任何异常,这可能是一种解决方法:

@Test(expected = Test.None.class /* no exception expected */)

或者,您可以禁止显示测试方法/测试类的警告:

@SuppressWarnings("squid:S2699")

推荐