Unlike previous versions of JUnit, JUnit 5 is composed of several different modules from three different sub projects
JUnit 5 = JUnit Platform + JUnit Jupiter + Junit Vintage
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.1.0</version>
<scope>test</scope>
</dependency>
JUnit 5 required Java 8 to work
The platform is responsible for launching testing frameworks on the JVM. It defines a stable and powerful interface between JUnit and its client such as build tools.
The final objective is how its clients get integrated easily with JUnit in discovering and executing the tests.
It also defines the TestEngine API for developing a testing framework that runs on the JUnit platform. By that, you can plug-in 3rd party testing libraries, directly into JUnit, by implementing custom TestEngine.
JUnit Jupiter is the combination of the new programming model and extension model for writing tests and extensions in JUnit 5
Support running JUnit 3 and JUnit 4 based tests on JUnit 5 platform
@BeforeAll
acts as a replacement for JUnit 4@BeforeClass
, specifies this method will execute once before all tests in the class@BeforeEach
acts as a replacement for JUnit 4@Before
, specifies this method will execute before each test method in the class@AfterAll
acts as a replacement for JUnit 4@AfterClass
, specifies this method will execute one after all tests in the class@AfterEach
acts as a replacement for JUnit 4@After
, specifies this method will execute after each test method in the class
@BeforeAll
public static void setUp() {
System.out.println("To be printed before all test");
}
@BeforeEach
public void init() {
System.out.println("To be printed before each test execution");
}
@AfterEach
public void tearDown() {
System.out.println("To be printed after each test execution");
}
@AfterAll
public static void done() {
System.out.println("To be printed after all tests execution");
}
@Disable
is a replacement for JUnit 4 @Ignore
@Disabled
public void testDisableAnnotation() {
System.out.println("This test will not be executed");
}
Test classes and test methods can declare custom display names with spaces, special characters, and even emojis that will be displayed by test runners and test reporting.
@Test
@DisplayName("╯°□°)╯ OMG I'm about to test a shark")
public void testFishCreation() {
Fish fish = new Fish();
String fishName = "Shark";
fish.setName(fishName);
assertEquals(fishName, fish.getName());
}
(work in progress)
(work in progress)
It is now possible to group assertions with assertAll()
which will report any failed assertions within the group with a MultipleFailuresError
@Test
public void testFishAllAssertion() {
// given
String name = "Golden Fish";
int price = 10;
//when
Fish fish = new Fish();
fish.setName(name);
fish.setPrice(price);
// then
assertAll("Fish Creation", () -> assertEquals(name, fish.getName()),
() -> assertEquals(price, fish.getPrice()));
}
What is the benefit of
assertAll()
over multiple assertions ?
Clearly we can write multiple assertions
assertEquals(name, fish.getName());
assertEquals(price, fish.getClass());
So what is the best place for assertAll()
?
assertAll
is that it always checks all of the assertions that are passed to it, no matter how many fail. If all pass, all is fine - if at least one fails you get a detailed result of all that went wrong
So if the fish.getName()
throws assertion error, the test would halt immediately, and you won't be able to see the assertion result of the fish price.
It (
assertAll
) is best used for asserting a set of properties that belong together conceptionally. Something where your first instinct would be, "I want to assert this as one".
With assertAll
, you will get a detail error of what went wrong
org.opentest4j.MultipleFailuresError: Fish Creation (2 failures)
expected: <sharky> but was: <Golden Fish>
expected: <150> but was: <10>
- JUnit 4 Exception Test
@Test(expected = IllegalArgumentException.class)
public void testSetPrice_ShouldThrowException_JUnit4Expression() {
int price = -1;
Fish fish = new Fish();
try {
fish.setPrice(price);
fail("should throw exception earlier");
} catch (IllegalArgumentException e) {
assertEquals("Illegal Price", e.getMessage());
throw e;
}
}
- JUnit 5 comes with new
assertThrows()
, which make the test more declarative
@Test
public void testSetPrice_ShouldThrowException_JUnit5Expression() {
int price = -1;
Fish fish = new Fish();
Throwable actualException = assertThrows(IllegalArgumentException.class, () -> {
fish.setPrice(price);
});
assertEquals("Illegal Price", actualException.getMessage());
}
Assumptions are typically used whenever it does not make sense to continue execution of a given test method — for example, if the test depends on something that does not exist in the current runtime environment.
assumeTrue()
assumeFalse()
assumeNoException()
assumeNotNull()
public class AppTest {
@Test
void testOnDev()
{
System.setProperty("ENV", "DEV");
Assumptions.assumeTrue("DEV".equals(System.getProperty("ENV")));
//remainder of test will proceed
}
@Test
void testOnProd()
{
System.setProperty("ENV", "PROD");
Assumptions.assumeTrue("DEV".equals(System.getProperty("ENV")), AppTest::message);
//remainder of test will be aborted
}
private static String message () {
return "TEST Execution Failed :: ";
}
}
(work in progress)
http://www.baeldung.com/junit-5
http://www.baeldung.com/junit-5-preview
https://howtodoinjava.com/junit-5/junit-5-assumptions-examples/
https://stackoverflow.com/questions/40796756/assertall-vs-multiple-assertions-in-junit5