Monday, 5 November 2018

JUnit5 Assertion Migration Strategy

JUnit5 Assertion Migration Strategy

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

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

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

Differences between JUnit 5 and JUnit 4

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

  • If I find and replace, then I can change the annotations.
  • 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.

e.g.

Junit 4 would be:

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

A direct conversion to Junit5 would be. But that would be incorrect because this means assert that the String “name should not be null” is not null, and if it is, 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 when they do present strategy for migrating, the strategy is a lot of manual work to check the assertions.

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

Going line, by line, while your code is ‘broken’ 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>
-->
  • Adding JUnit 5 with the backwards 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 was 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

Assertion Abstractions

Since Abstractions are the main issue I face, I thought I might investigate 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.

Perhaps migrate to AssertJ or Hamcrest first?

AssertJ

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

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

AssertJ has migration scripts for helping migrate

I would have to read these to evaluate them first.

Hamcrest

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

https://github.com/hamcrest/JavaHamcrest/wiki/The-Hamcrest-Tutorial

Branch By Abstraction

Since I want to evaluate the different libraries.

I could use a Branch by Abstraction approach.

Currently my code has

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

I only use a subset of “Assert” so 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, 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 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, I could experiment with different implementations. I could create a 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 even more flexible by coding to an interface and having the Assert wrapper be 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 see all the code on github:

And the Video

https://youtu.be/K7EhTpzu59M

Live Tutorial for Migrating from JUnit 4 to JUnit 5 Assertions via Abstraction Layers

Friday, 13 July 2018

MVP and API Thinking When Coding


TLDR; Apply MVP principles when coding. Code to the API first. The API is internal before it is external. Unit tests with classes. In code testing with classes in combination. In code API testing. External HTTP API Testing. And then if necessary -In memory and process HTTP API testing. GUI.



A long time ago, in a town which I no longer live in, I wrote a tool called Compendium-TA



Commercially that was a disaster: it was self funded, it took a long time to write and I made some poor technology decisions.



I learned MVP and API First Thinking the hard way. I’ll try and explain within.



Monday, 7 May 2018

Some Similarities Between Java And JavaScript

TLDR: Learn one programming language and you have already learned parts of other languages. You can speed up learning other languages by learning the differences.

I wrote a bunch of code in Java in my Test Tool Hub for generating CounterStrings.

I thought it would be useful to have it online and written in JavaScript.


Thursday, 26 April 2018

Overview of Spark and HTTP Testing with JUnit

TLDR: Spark is static so having it run in an @BeforeClass allows HTTP request testing to begin.

I use Spark as the embedded web server in my applications. I also run simple HTTP tests against this as part of my local maven build. And I start Spark within the JUnit tests themselves. In this post I’ll show how.


Wednesday, 25 April 2018

When would I choose basic HTTP libraries rather than using RestAssured?

TLDR: when I have a small set of HTTP use-cases, and I’m working on fast in-build HTTP integration verification then I’ll probably use HttpURLConnection

I do receive a question fairly often like:

  • “Why would you ever use basic HTTP libraries rather than Rest-Assured?”
  • “When would you choose to use basic HTTP libraries instead of Rest-Assured?”

And other variants.

I’ll try to answer that in this post.


Tuesday, 24 April 2018

Migrating from JAXB XML processing to XStream

TLDR: refactored to isolate XML processing, configured XStream in code, removed all annotations, added XML header, wrote less code

I have a small REST API application which uses Spark and GSON and JAXB. I haven’t released this to Github yet but I did release some of the example externally executed integration verification code for it.

When trying to package this for Java 1.9 I encountered the, now standard, missing JAXB, libraries. So I thought I’d investigate another XML library.


Monday, 9 April 2018

Changes to Automating a REST API code base for Java 1.9 RestAssured 3.0.7

TLDR: For Java 1.9 upgrade Rest Assured to version 3.0.6 0r 3.0.7. I also had to add some JAXB Maven Dependencies

I my book Automating and Testing a REST API I used Java 1.8 and Rest Assured version 3.0.1. This was in the days prior to Java 1.9 becoming the default.

I recently checked the code against Java 1.9 and had to make some changes to update Rest Assured.

Sunday, 8 April 2018

How to learn Java with Exploratory Programming

TLDR: Learn Java by taking advantage of code completion and JavaDoc in the IDE to explore classes with JUnit Tests

In my book Java For Testers I encourage the reader to experiment when learning Java by writing small JUnit tests to explore classes. I’m going to expand on that concept in this blog post and the associated video.