SonarQube 问题“向此测试用例添加至少一个断言”以使用断言进行单元测试?

问题描述 投票:0回答:4

我在使用 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 专门寻找什么来检查是否已为每个测试做出断言?

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

java unit-testing junit sonarqube
4个回答
18
投票

来自

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

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

对于SonarQube在此类情况下提出的问题,您可以安全地将其标记为

Won't Fix

关于检测到的断言,该规则将以下(单元测试)框架中常用的

assert
/
fail
/
verify
/
expect
方法视为断言:

  • JUnit
  • 节(1.x 和 2.x)
  • 断言J
  • 哈姆克雷斯特
  • 莫基托
  • 春天
  • EasyMock

12
投票

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

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

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

@SuppressWarnings("squid:S2699")

2
投票

我过去做过的一件事是让辅助方法返回 true,并断言:

@Test
public void testSomeThings() {
    Thing expected = // . . .

    Thing actual = service.methodReturningThing(42);

    assertTrue(assertViolation(expected, actual));
}

private boolean assertViolation(Thing expected, Thing actual) {
    assertEquals(expected.getName(), actual.getName());
    assertEquals(expected.getQuest(), actual.getQuest());
    assertEquals(expected.getFavoriteColor(), actual.getFavoriteColor());
    return true;
}

我讨厌这个,但我更讨厌重复的代码。

我们有时做的另一件事就是简单地将 SonarQube 中的任何此类异议标记为“无法修复”,但我也讨厌这样做。


2
投票

有时候你不需要任何代码或断言,例如Spring Boot上下文加载成功的测试。在这种情况下,为了防止在您不希望测试中抛出任何异常时出现声纳问题,您可以使用这部分代码:

@Test
void contextLoads() {
    Assertions.assertDoesNotThrow(this::doNotThrowException);
}

private void doNotThrowException(){
    //This method will never throw an exception
}

或单行解决方案(2023 年 1 月更新)

@Test
void contextLoads() {
    Assertions.assertDoesNotThrow(()->{});
}
© www.soinside.com 2019 - 2024. All rights reserved.