Mixing JUnit 4 and JUnit 5 tests
Thanks to the new architecture that JUnit 5 introduces it is possible to run both JUnit 4 and JUnit 5 tests in the same project. JUnit 5 consists of three different sub-projects:
- Platform – to support the implementation of various test engines.
- Jupiter – the engine to run JUnit 5 tests.
- Vintage – the engine to run JUnit 4 tests.
Maven Setup
Taking this into consideration you will need to add three different dependencies to your project, junit-platform-launcher, junit-jupiter-engine, and junit-vintage-engine.
<dependency> <groupId>org.junit.platform</groupId> <artifactId>junit-platform-launcher</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>5.2.0</version> </dependency> <dependency> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> <version>5.2.0</version> </dependency>
If you have some very custom requirements, you can always write your own custom engine and include that one as well.
Running tests with IntelliJ IDEA
For IDEA it is enough for Vintage and Jupiter to be on the classpath.
import org.junit.After; import org.junit.Before; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class Junit5TestsMixedBefores { /** * This @Before is NOT going to be executed. */ @Before public void before() { System.out.println("@Before"); } @BeforeEach public void beforeEach() { System.out.println("@BeforeEach"); } @Test public void simpleJunit5Test() { System.out.println(" Simple Junit 5 test."); } @AfterEach public void afterEach() { System.out.println("@AfterEach"); } /** * This @After is NOT going to be executed. */ @After public void after() { System.out.println("@After"); } }
When you run this example the @Before and @After methods will not be executed. This is the output that you get:
@BeforeEach Simple Junit 5 test. @AfterEach
It is obvious why. In this test class, there is only a single JUnit 5 test. @Before and @After methods run only before and after JUnit 4 tests only. If you add a JUnit 4 test to this same class:
@org.junit.Test public void simpleJunit4Test() { System.out.println(" Simple Junit 4 test."); }
the @Before and @After methods will be run. This is because each engine has its turn. Vintage engine discovers and runs the JUnit 4 tests. Jupiter runs its own discovery and execution phases where it discovers and executes JUnit 5 tests only. So not that you can only run JUnit 4 and JUnit 5 tests in the same project, you can also do that in the same test class.
Running tests with Maven
Running a simple mnv install
does not run any tests. Maven needs a bit more in order to run the tests:
<build> <plugins> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.21.0</version> <dependencies> <dependency> <groupId>org.junit.platform</groupId> <artifactId>junit-platform-surefire-provider</artifactId> <version>1.2.0</version> </dependency> </dependencies> </plugin> </plugins> </build>
If you run the test now both JUnit 4 and JUnit 5 tests will be executed.
Using JUnit 4 to run JUnit 5 tests
Today most of the IDEs and build tools support JUnit 5. However, if you have a build system that can run JUnit 4 tests but does not support the JUnit Platform directly, you can still use it to run JUnit 5 tests. That is thanks to the JUnitPlatform runner that was introduced for forward-compatibility.
When you annotate a JUnit 5 class with the @RunWith(JUnitPlatform.class) it will be run as a JUnit 4 test but with JUnit 5 features. Not all features are supported though. Read more about that in the JUnit 5 User Guide.
Example
If you run mnv install
without adding the junit-platform-surefire-provider dependency as in the previous example, it should not run any Junit 5 tests. But if you annotate those tests with @RunWith(JUnitPlatform.class) they will run. By adding the annotation they will be treated as JUnit 4 tests.
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; @RunWith(JUnitPlatform.class) public class SimpleJUnit5Test { @BeforeEach public void beforeEach() { System.out.println("@BeforeEach."); } @Test public void shouldExecuteJunit5Methods() { System.out.println(" Forward compatible test."); } @AfterEach public void afterEach() { System.out.println("@AfterEach."); } }
This is a JUnit 5 test but thanks to the JUnitPlatform runner maven will run it together with all other JUnit 4 tests.
Running org.igorski.SimpleJUnit5Test @BeforeEach. Forward compatible test. @AfterEach. Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.31 sec