Migrating from JUnit 4 to JUnit 5 is a lengthy manual process that you can make easier with these tools.
JUnit is by far the most popular unit testing framework for Java (84% of Java developers use it). While its current generation JUnit 5 has been available since 2017, the previous version JUnit 4 is still widely used. At the time of writing, about 8M Java files on GitHub contain JUnit 4 tests, while only about 3M contain JUnit 5 tests.
Upgrading to JUnit 5 brings a range of benefits, including:
- More flexibility with JUnit 5’s support for modular and extensible architectures
- Updated annotations including
@BeforeEach
,@AfterEach
,@BeforeAll
, and@AfterAll
- Flexible assertions class
- Powerful testing with built-in support for extensions
- Support for parameterized testing, conditional test execution, and dynamic tests (for testing in runtime)
- Support for tagging and filtering tests
👀 Differences between JUnit 4 vs JUnit 5: why upgrade?
For a complete overview of differences and a step-by-step description of a manual migration process, see our migration guide.
While migrating from JUnit 4 to 5 isn’t rocket science, it can take quite a bit of time in the case of large projects. There are several tools out there to (semi-) automate the upgrade process.
JUnit 4 to 5 migration tools
A note on using LLMs to migrate JUnit 4 to 5
While Large Language Models can be useful in tackling the upgrade from JUnit 4 to JUnit 5, they don’t provide deterministic results and suffer from problems such as hallucinations. Because of that, there’s some chance you’ll end up spending more time reworking your prompts and fixing code than the migration would have taken manually or than using one of the tools outlined below. In this post, we only look at deterministic solutions i.e. those that provide the exact same output for the exact same input every time. Tools are listed in an arbitrary order.
💡 A blog post series on LLM benchmarking Read all the other posts in Symflower’s series on LLM evaluation, and check out our latest deep dive on the best LLMs for code generation.
OpenRewrite
OpenRewrite is an automated refactoring ecosystem with predefined refactoring recipes (e.g. predefined, ready-to-use blueprints to transform code) like migration to Java 21, migration from Spring Boot 2 to 3, etc. OpenRewrite is a community-driven, open-source project, but is maintained by, and can be used with Moderne’s proprietary toolset for additional enterprise features (such as faster processing, multi-repo support, integrated team communication, etc).
OpenRewrite can be used to migrate large codebases to JUnit 5. It works by creating a Lossless Semantic Tree (LST) from your source code to execute the migration refactoring. Here’s a description of the migration process using one of OpenRewrite’s recipes.
Recipes cover a whole range of tasks including:
- Upgrading to later Java versions
- General code refactorings
- Static code analysis and checkstyle issue resolution
- Spring Boot 1 to 2 migration.
Symflower
Symflower is the only tool that offers fully automated migration from JUnit 4 to JUnit 5. Using Symflower enables a quick and efficient migration with no manual changes required. It’s an all-in-one solution that migrates code, packages, and dependencies.
Symflower is a CLI tool that covers a range of migration rules to update JUnit annotations, assertions, assumptions in your code. See the documentation for a detailed list of currently supported rules).
For an example of using Symflower in action, check out the guide in the tool’s documentation.
Migration with IntelliJ IDEA
IntelliJ IDEA’s migration process can be considered a semi-automatic one. For instance, you’ll need to manually add JUnit 5 dependencies, and then use IntelliJ’s code suggestions to migrate chunks of code step by step.
Migrating with IntelliJ IDEA involves using the Find action to migrate JUnit 4 tests to JUnit 5, and using regex to remove references to JUnit 4 classes. More complex tests will need to be migrated manually.
Here’s the full tutorial for using IntelliJ IDEA to migrate from JUnit 4 to 5. There’s also the “Migrate” refactoring to make the process more simple. “Migrate” enables you to create a set of migration rules for a codebase. The tool also lets you edit existing migration rules to modify predefined settings, ensuring you can customize the migration process as needed.
migrate-to-junit5
migrate-to-Junit5 provides an “almost” automatic way to upgrade your codebase to JUnit 5. The tool relies on GNU AWK. You’ll run it from a Docker image so no additional dependencies are required. The process is described in this blog post.
migrate-to-junit5 does the following:
- Migrate imports to the new JUnit 5 package names
- Update annotations e.g.
@Before
->@BeforeEach
,@After
->@AfterEach
,@Ignore
->@Disabled
, etc. - When using the following runners with
@RunWith
:SpringRunner/SpringJUnit4ClassRunner
is transformed toSpringExtension
MockitoJUnitRunner
is transformed toMockitoExtension
- Test code updated to use
assertThrows()
when appropriate (when declaring exceptions the code should throw).
Using the tool is fairly straightforward: build the docker image, manually update pom.xml
with dependencies, then use your editor to format code, optimize imports, and fix lambdas. The tool relies on IntelliJ’s built-in functionality for inspecting and updating code (e.g. when unnecessary curly braces are introduced by the migration).
Note that this tool doesn’t support @Rule
, and you’ll need to remove unused imports manually. Another limitation is that in some situations, curly braces can confuse the script, so you’ll need to meticulously check the migrated code.
jSparrow
jSparrow is a code cleanup and refactoring tool for Java code that works with Eclipse. Like OpenRewrite, it offers a range of auto-refactor rules.
To migrate from JUnit 4 to 5, you’ll need to use:
- Replace JUnit 4 Annotations with JUnit Jupiter
- Replace JUnit 4 Assertions with JUnit Jupiter
- Replace JUnit 4 Assumptions with JUnit Jupiter
- Replace JUnit 4 Category with JUnit Jupiter Tag
- Replace JUnit Timeout Annotation Property with assertTimeout
- Replace JUnit Expected Annotation Property with assertThrows
- Replace JUnit ExpectedException with assertThrows
- Replace JUnit assertThat with Hamcrest
- Replace JUnit Assumptions with Hamcrest JUnit
You’ll need to combine several of jSparrow’s available rules for a successful migration. Migration with jSparrow can be considered a semi-manual process: while these auto-refactor rules are useful, they don’t come packaged into a “JUnit 4 to JUnit 5” set, you’ll need to manually select and use the appropriate ones.