Java – SonarQube issue “Add at least one assertion to this test case” for unit test with assertions

javajunitsonarqubeunit testing

I'm having issues with SonarQube raising issues with several of my unit tests, prompting the following issue:

Add at least one assertion to this test case.

Each test case resembles this format (where a number of assertions are delegated to a method with common assertions, to avoid duplication):

@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());
}

Now, obviously I could just pull the three assertions out of the private method and put them in the test method – but I'm performing the same checks (on different fields) multiple times.

So, I thought I'd try to emulate the behaviour of the assertion methods, by (re) throwing an 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;
    }
 }

Unfortunately, this approach does not work either.

What's special about the JUnit assert methods / what is SonarQube looking for specifically to check that an assertion has been made for each test?

Alternatively – are there other approaches to achieve the same end result (avoiding duplicating the shared assertion code over and over)?

Best Answer

The rule S2699 (Tests should include assertions) from the SonarQube Java Analyzer does not perform cross-procedural analysis and only explore body of methods being identified as test method (usually annotated with @Test).

Consequently, if the only assertions which will be called when executing the test method are done by a dedicated method (to avoid duplication), then the rule will raise an issue. This is a known limitation of the rule and we will deal with it only when we will be able to efficiently perform cross-procedural analysis.

Regarding the issues raised by SonarQube on such cases, you can safely mark them as Won't Fix.

Regarding the detected assertions, the rule consider as assertions the usual assert/fail/verify/expect methods from the following (unit test) frameworks :

  • JUnit
  • Fest (1.x & 2.x)
  • AssertJ
  • Hamcrest
  • Mockito
  • Spring
  • EasyMock