JUnit 5 aims to adapt the Java 8 style of coding and to be more robust and flexible than JUnit 4. In this post, JUnit 5 vs JUnit 4, we will focus on some major differences between JUnit 4 and JUnit 5.
1. Different Annotations
Most of the annotations in both versions are the same, but a few differ. Here is a quick comparison.
Feature | JUnit 4 | Junit 5 |
---|---|---|
Declare a test method | @Test | @Test |
Execute before all test methods in the current class | @BeforeClass | @BeforeAll |
Execute after all test methods in the current class | @AfterClass | @AfterAll |
Execute before each test method | @Before | @BeforeEach |
Execute after each test method | @After | @AfterEach |
Disable a test method/class | @Ignore | @Disabled |
Test factory for dynamic tests | NA | @TestFactory |
Nested tests | NA | @Nested |
Tagging and filtering | @Category | @Tag |
Register custom extensions | NA | @ExtendWith |
2. More differences between JUnit 5 and JUnit 4
2.1. Architecture
JUnit 4 has everything bundled into a single jar file.
JUnit 5 is composed of 3 sub-projects i.e. JUnit Platform, JUnit Jupiter and JUnit Vintage.
- JUnit Platform: It defines the TestEngine API for developing new testing frameworks that run on the platform.
- JUnit Jupiter: It has all new JUnit annotations and TestEngine implementation to run tests written with these annotations.
- JUnit Vintage: To support running JUnit 3 and JUnit 4 written tests on the JUnit 5 platform.
2.2. Required JDK Version
Junit 4 requires Java 5 or higher.
Junit 5 requires Java 8 or higher.
2.3. Assertions
In Junit 4, org.junit.Assert has all assert methods to validate expected and resulting outcomes.
They accept extra parameters for error messages as the FIRST argument in the method signature. e.g.
public static void assertEquals(long expected, long actual)
public static void assertEquals(String message, long expected, long actual)
In JUnit 5, org.junit.jupiter.Assertions contain most of assert() methods including additional assertThrows()
and assertAll()
methods.
JUnit 5 assertions methods also have overloaded methods to support parsing error messages to be printed in case test fails e.g.
public static void assertEquals(long expected, long actual)
public static void assertEquals(long expected, long actual, String message)
public static void assertEquals(long expected, long actual, Supplier messageSupplier)
2.4. Assumptions
In Junit 4, org.junit.Assume contains methods for stating assumptions about the conditions in which a test is meaningful. It has the following five methods:
- assumeFalse()
- assumeNoException()
- assumeNotNull()
- assumeThat()
- assumeTrue()
In Junit 5, org.junit.jupiter.api.Assumptions contain methods for stating assumptions about the conditions in which a test is meaningful. It has the following three methods:
- assumeFalse()
- assumingThat()
- assumeTrue()
2.5. Tagging and Filtering
In Junit 4, @category
annotation is used.
In Junit 5, @tag
annotation is used.
2.6. Test Suites
In Junit 4, @RunWith
and @Suite
annotation. e.g.
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({
ExceptionTest.class,
TimeoutTest.class
})
public class JUnit4Example
{
}
In Junit 5, @Suite
, @SelectPackages
and @SelectClasses
e.g.
import org.junit.platform.runner.JUnitPlatform;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.runner.RunWith;
@Suite
@SelectPackages("com.howtodoinjava.junit5.examples")
public class JUnit5Example
{
}
2.7. Non-public Test Methods are Allowed
- JUnit 5 test classes and test methods are not required to be public. We can now make them package protected.
JUnit internally uses reflection to find test classes and test methods. Reflection can discover them even if they have limited visibility so there is no need for them to be public. - JUnit test classes also can have non-public constructors. They can even have arguments. It means having a public no-args constructor is not mandatory in JUnit 5.
class AppTest {
private AppTest(TestInfo testInfo) {
System.out.println("Working on test " + testInfo.getDisplayName());
}
@Test
void test(){
assertTrue(true);
}
}
2.8. 3rd Party Integration
In Junit 4, there is no integration support for 3rd party plugins and IDEs. They have to rely on reflection.
JUnit 5 has a dedicated sub-project for this purpose i.e. JUnit Platform. It defines the TestEngine
API for developing a testing framework that runs on the platform.
3. Conclusion
In this JUnit tutorial, we learned the important differences between JUnit 4 and JUnit 5 frameworks and the tests written with them. Even though there are many differences under the hood, the main difference is the modularity introduced in JUnit 5 and support for writing custom runtime engines by 3rd party providers.
Happy Learning !!