SonarQube问题"为这个测试用例添加至少一个断言"用于带断言的单元测试?

Mic*_*ael 8 java junit unit-testing sonarqube

我遇到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());
}
Run Code Online (Sandbox Code Playgroud)

现在,显然我可以将三个断言从私有方法中拉出来并将它们放入测试方法中 - 但我正在多次执行相同的检查(在不同的字段上).

所以,我认为我会尝试模仿断言方法的行为,通过(重新)抛出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;
    }
 }
Run Code Online (Sandbox Code Playgroud)

不幸的是,这种方法也不起作用.

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

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

Mic*_*eam 6

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

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

关于SonarQube针对此类案例提出的问题,您可以安全地将其标记为Won't Fix.

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

  • JUnit的
  • 巨星(1.x和2.x)
  • AssertJ
  • Hamcrest
  • 的Mockito
  • 弹簧
  • EasyMock的

  • 消息是否应该改写为“ _,从受支持的框架到此测试用例中至少添加一个断言。_”,使其更加直观? (2认同)
  • @Michael-SonarSourceTeam 我们看到的结果似乎表明分析器现在正在 OP 的场景中执行跨程序分析,但是无法通过 google 找到任何内容来确认这一点。您能提供更新吗? (2认同)

Chi*_*hin 5

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

@Test(expected = Test.None.class /* no exception expected */)
Run Code Online (Sandbox Code Playgroud)

或者,您可以取消测试方法/测试类的警告:

@SuppressWarning("squid:S2699")
Run Code Online (Sandbox Code Playgroud)