Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@Test(expected = Exception.class) or Assertions.assertThrows(...) or assertThatThrownBy(..) which one is recommended?

I am using JUnit 4.12

<dependency>
    <groupId>pl.pragmatists</groupId>
    <artifactId>JUnitParams</artifactId>
    <version>1.0.5</version>
    <scope>test</scope>
</dependency>

I wanted to know which one is most recommended to use @Test(expected = Exception.class) or Assertions.assertThrows(...)

like image 758
AVN Avatar asked Dec 18 '22 19:12

AVN


1 Answers

With JUnit 4.12 there are several ways to test code for expected exceptions.

try-catch

We can simply use Java's try-catch.

@Test
public void testInvalidData() {
    prepareTestData();

    try {
        userService.fetchUser(1234);
        Assert.fail("IllegalArgumentException not thrown");
    } catch (IllegalArgumentException expected) {
    }
}

Whenever we use this approach, we have to make sure to call Assert.fail(...) in case the expected exception was not thrown.

Annotation Attribute

As you already mentioned, the @Test has an attribute to declare the expected exception.

@Test(expected = IllegalArgumentException.class)
public void testInvalidData() {
    prepareTestData();

    // should throw IllegalArgumentException
    userService.fetchUser(1234);
}

The test is green if the test method throws the exception. The test is red if the test method throws no exception or a different exception.

This has one big disadvantage: We can't figure out which instruction throws the IllegalArgumentException. If prepareTestData(); throws the exception, the test is still green.

Rule ExpectedException

JUnit 4 contains the built-in rule ExpectedException. (please remember that JUnit 5 uses extensions instead of rules)

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void testInvalidData() {
    prepareTestData();

    thrown.expect(IllegalArgumentException.class);
    userService.fetchUser(1234);
}

This approach is similar to try-catch and @Test(expected = ...), but we can control from which point the exception is expected.

assertThrows

AssertJ and JUnit 5 provide methods to assert that a specific code block throws a specific exception.

@Test
public void testInvalidData() {
    prepareTestData();

    Assertions.assertThrows(IllegalArgumentException.class, () -> {
        userService.fetchUser(1234);
    });
}

Assertions.assertThrows also returns the exception object to execute further asserts, e.g. to assert the message.

Summary

I try to use assertThrows as often as possible because the test code gets both readable and flexible. But all the other mentioned approaches are also valid if correctly used.

like image 115
Roland Weisleder Avatar answered Apr 05 '23 22:04

Roland Weisleder