JUnit Jupiter
This module comprises new programming and extension models for writing tests in JUnit 5. New annotations compared to JUnit Jupiter 4 are explained in detail in the sections below.
Basic Annotations
We divided this section into the following execution groups to discuss the new annotations: before the tests, during the tests (optional), and after the tests:
@BeforeAll and @BeforeEach
Here's an example of simple code that should be run before the main test cases:
@BeforeAll
static void setup() {
log.info("@BeforeAll: executes once before all test methods in this class");
}
@BeforeEach
void init() {
log.info("@BeforeEach: executes before each test method in this class");
}
It's important to note that the @BeforeAll annotation requires a static method; otherwise, the code will not compile.
@DisplayName and @Disabled
Let's move on to some new test-optional methods now:
@DisplayName("Single test successful")
@Test
void testSingleSuccessTest() {
log.info("Success");
}
@Test
@Disabled("Not implemented yet")
void testShowSomething() {
}
As you can see, we can use new annotations to change the display name or disable the method with a comment.
@AfterEach and @AfterAll
Finally, consider the methods associated with operations after a test has been completed:
@AfterEach
void tearDown() {
log.info("@AfterEach: executed after each test method.");
}
@AfterAll
static void done() {
log.info("@AfterAll: executed after all test methods.");
}
Please keep in mind that the @AfterAll method must also be a static method.
Assertions
Assertions have been moved to org.junit.jupiter.api.Assertions and greatly improved. Lambdas can now be used in assertions:
@Test
void lambdaExpressions() {
List numbers = Arrays.asList(1, 2, 3);
assertTrue(numbers.stream()
.mapToInt(i -> i)
.sum() > 5, () -> "Sum should be greater than 5");
}
Although the example above is simple, using a lambda expression for the assertion message has the advantage of being lazy evaluated, which can save time and resources if the message construction is time-consuming.
The assertAll() can now be used to group assertions, and any failed assertions within the group will be reported with a MultipleFailuresError:
@Test
void groupAssertions() {
int[] numbers = {0, 1, 2, 3, 4};
assertAll("numbers",
() -> assertEquals(numbers[0], 1),
() -> assertEquals(numbers[3], 3),
() -> assertEquals(numbers[4], 1)
);
}
As a result, it's now safer to make more complex assertions because we'll be able to pinpoint the precise location of any failure.
Assumptions
When certain conditions are met, assumptions are used to run tests. This is typically used for external conditions that must be met for the test to run correctly but are unrelated to the subject of the test.
With assumeTrue(), assumeFalse(), and assumingThat(), we can declare an assumption:
@Test
void trueAssumption() {
assumeTrue(5 > 1);
assertEquals(5 + 2, 7);
}
@Test
void falseAssumption() {
assumeFalse(5 < 1);
assertEquals(5 + 2, 7);
}
@Test
void assumptionThat() {
String someString = "Just a string";
assumingThat(
someString.equals("Just a string"),
() -> assertEquals(2 + 2, 4)
);
}
A TestAbortedException is thrown if an assumption fails, and the test is simply skipped.
Lambda expressions are also understood by assumptions.
Exception Testing
In JUnit 5, there are two ways to test for exceptions, both of which can be done with the assertThrows() method:
@Test
void shouldThrowException() {
Throwable exception = assertThrows(UnsupportedOperationException.class, () -> {
throw new UnsupportedOperationException("Not supported");
});
assertEquals(exception.getMessage(), "Not supported");
}
@Test
void assertThrowsException() {
String str = null;
assertThrows(IllegalArgumentException.class, () -> {
Integer.valueOf(str);
});
}
The first example verifies the details of the thrown exception, while the second example verifies the exception type.
Test Suites
To continue exploring JUnit 5's new features, we'll look at the concept of aggregating multiple test classes into a test suite so that we can run them all at once. To create test suites, JUnit Jupiter 5 provides two annotations: @SelectPackages and @SelectClasses.
Keep in mind that most IDEs don't support these features at this time.
Let's start with the first one:
@RunWith(JUnitPlatform.class)
@SelectPackages("com.baeldung")
public class AllUnitTest {}
When running a test suite, @SelectPackage is used to specify the names of packages to be selected. It will run all of the tests in our example. The @SelectClasses annotation is used to specify which classes should be used when running a test suite:
@RunWith(JUnitPlatform.class)
@SelectClasses({AssertionTest.class, AssumptionTest.class, ExceptionTest.class})
public class AllUnitTest {}
The above class, for example, will generate a suite of three test classes. Please keep in mind that the classes do not need to be in one package.
Dynamic Tests
The final topic we'll cover is JUnit 5's Dynamic Tests feature, which allows us to declare and run test cases that are generated at runtime. Dynamic Tests, in contrast to Static Tests, which define a fixed number of test cases at compile time, allow us to define test cases dynamically during runtime.
A factory method annotated with @TestFactory can generate dynamic tests. Take a look at the following code:
@TestFactory
public Stream<DynamicTest> translateDynamicTestsFromStream() {
return in.stream()
.map(word ->
DynamicTest.dynamicTest("Test translate " + word, () -> {
int id = in.indexOf(word);
assertEquals(out.get(id), translate(word));
})
);
}
This is a very simple and easy-to-understand example. We want to use two ArrayLists, named in and out, to translate words. A Stream, Collection, Iterable, or Iterator must be returned by the factory method. We went with a Java 8 Stream in our case.
It's important to remember that @TestFactory methods can't be private or static. The number of tests is variable and is determined by the size of the ArrayList.
Check out JUnit Interview Questions here.
Frequently Asked Questions
-
What is @test in Jupiter?
The annotation @test is used to indicate that the method is a test method.
-
What is Assertions in Jupiter?
Assertions is a library of useful methods for asserting conditions in tests.
-
What is @Disabled in Jupiter?
The annotation @Disabled is used to indicate that a test class or method is currently disabled and should not be executed.
-
What is @AfterAll in Jupiter?
The annotation @AfterAll indicates that the annotated method should be run after all tests in the current test class.
-
What is @AfterEach in Jupiter?
The annotation @AfterEach indicates that the annotated method should be called after each of the test class's @Test, @RepeatedTest, @ParameterizedTest, @TestFactory, and @TestTemplate methods.
Conclusions
In this article, we presented a quick overview of the changes that are coming with JUnit 5 and JUnit Jupiter. We saw basic annotations in Jupiter.
We hope that this blog has helped you enhance your knowledge and if you would like to learn more, check out our articles on Coding Ninjas Studio. Do upvote our blog to help other ninjas grow. Happy Coding!