DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Culture and Methodologies
  3. Agile
  4. JUnit5 Assertion Migration Strategy

JUnit5 Assertion Migration Strategy

Rather than migration your assertions line by line, create an abstraction class to represent the new implementation and then perform inline refactoring.

Alan Richardson user avatar by
Alan Richardson
·
Nov. 06, 18 · Tutorial
Like (2)
Save
Tweet
Share
11.03K Views

Join the DZone community and get the full member experience.

Join For Free

I’m experimenting with migrating my projects to JUnit 5.

Many of the “how to migrate to JUnit 5” blog posts show many differences, but not much strategy. I used a Branch-By-Abstraction strategy to migrate JUnit 4 assertions. This allowed me to experiment with using JUnit5 assertions or AssertJ assertions.

Difference Between JUnit 5 and JUnit 4

The main differences between JUnit4 and JUnit5 seem to pertain to annotations, rules, and assertions.

  • If I find and replace, then I can change the annotations.
  • For assertions, if they are statically imported, I could find and replace the static import statements.

But, assertions have the issue that in JUnit5, the messages have to go at the end of the parameter call list.

For example, JUnit 4 would be:

Assert.assertNotNull("name should not be null", name);


A direct conversion to JUnit5 would be similar. But that would be incorrect because this means that we assert that the String “name should not be null” is not null, and if it is, we show the error message in the variable name, which is the opposite from the current JUnit4 test.

Assertions.assertNotNull("name should not be null", name);


Assertions are the main issue I have to solve in my migration.

Useful Articles, but Not Viable Strategies

The following articles are all useful, but they do present a strategy for migrating. The strategy involves a lot of manual work to check the assertions.

  • https://junit.org/junit5/docs/current/user-guide/#migrating-from-junit4 JUnit 5 docs have migration tips
  • https://www.baeldung.com/junit-5-migration explains differences but not “how to migrate”
  • https://vocabhunter.github.io/2017/10/17/migrating-to-junit-5.html explains some IDE shortcuts for switching assertion arguments, but this has to be done on a line-by-line basis
  • Annotations can be found and replaced
  • https://www.petrikainulainen.net/junit-5-the-ultimate-resource/
  • https://medium.com/@ramtop/porting-your-existing-tests-to-junit5-1adfd7f0ea51

None of these seem to present a strategy I like for migrating to JUnit 5.

Going line by line, while your code is ‘broken,’ it doesn’t seem like an effective approach.

Basic Steps

The first steps I took were:

Commenting out JUnit 4 in the pom.xml:

<!--
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>
        -->


Next, we added JUnit 5 with the backward compatibility functionality in the vintage engine:

<dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.3.1</version>
        </dependency>
         <dependency>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
            <version>5.3.1</version>
        </dependency>


This provided a quick view of what doesn’t work. For more complicated projects, we might also need to add the migration support package.

You can find all the Migration tips on the JUnit 5 site:

  • https://junit.org/junit5/docs/current/user-guide/#migrating-from-junit4

Assertion Abstractions

Since abstractions are the main issue I face, I thought I might investigate the Assertion libraries. After all, if I’m going to have to change all the assertions, perhaps I should change them all to an Assertion library.

In fact, I might even migrate to AssertJ or Hamcrest first?

AssertJ

AssertJ uses an Assertions package and has a fluent interface so that it might be easier for beginners because of code completion.

AssertJ has ‘soft’ assertions to assert on all assertions and report on all even when one fails. This is a functionality in JUnit 5, as well, but I don’t need to use JUnit 5 Assertions to get it.

AssertJ has migration scripts that help it migrate. I would have to read these first to evaluate them.

Hamcrest

I have used Hamcrest before. But, I chose to stick to JUnit 4 because it was simpler and had more code completion.

Branch by Abstraction

Since I want to evaluate the different libraries, I could use a Branch-by-Abstraction approach.

Currently, my code looks like the following:

Assert.assertNotNull("name should not be null", name);


I only use a subset of “Assert” so that I could easily create an “Assert” class, which allows me to migrate to JUnit 5 without changing my code e.g.

package uk.co.compendiumdev.junitmigration.tojunit5;

import org.junit.jupiter.api.Assertions;

public class Assert {
    public static void assertNotNull(final String message, final String actual) {
    Assertions.assertNotNull(actual, message);
  }
}


If I had the above, then I could simply import that into my Test Class. There is no need to change the code in my Test Class, and then, I have used JUnit 5 Assertions.

If I used this throughout my code base, then instead of working on Assertion migration at a line-by-line level, I could use IntelliJ to perform an inline refactor for each method and it would change my JUnit4 code from:

Assert.assertNotNull("name should not be null", name);


And, it would change it to JUnit 5:

Assertions.assertNotNull(name, "name should not be null");


I haven’t seen this strategy mentioned in any of the migration blogs that I read.

Branch By Abstraction to AssertJ

Because this is a Branch-by-Abstraction migration, I could experiment with different implementations. I could create an AssertJ implementation of my Assert abstraction:

package uk.co.compendiumdev.junitmigration.toassertj;

import static org.assertj.core.api.Assertions.assertThat;

public class Assert {

    public static void assertNotNull(final String message, final String actual) {
        assertThat(actual).isNotNull().overridingErrorMessage(message);
    }
}


By changing the imports, I could switch between AssertJ or JUnit5 without changing my test code until I am happy to settle on one of the approaches.

I could clearly make this more flexible by coding to an interface and having the Assert wrapper as a configurable factory, which switches between the two, but I don’t need that degree of complexity.

Branch-By-Abstraction Strategy for Assertion Migration

This seems to be a simpler approach to assertion migration than I’ve seen mentioned.

This approach is open to me even if I statically import the methods because I can statically import the methods from my abstraction class instead of the main library.

I’m not sure why this isn’t the most communicated migration approach.

I created a video showing this approach in action below, and you can also check out all the code on GitHub:

I hope you enjoy the video!


This article was syndicated from blog.eviltester.com. Author Alan Richardson is an Agile Software Development and Testing Consultant he has written 4+ books including Dear Evil Tester, Automating and Testing a REST API, Java For Testers. He has created 6+ online training courses covering Technical Web Testing, Selenium WebDriver and other topics. He is a prolific content creator on his blog, Youtube and Patreon.

Assertion (software development) JUnit agile

Published at DZone with permission of Alan Richardson, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Easy Smart Contract Debugging With Truffle’s Console.log
  • Agile Transformation With ChatGPT or McBoston?
  • The 31 Flavors of Data Lineage and Why Vanilla Doesn’t Cut It
  • Deploying Java Serverless Functions as AWS Lambda

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: