Don't use AssertJ

Aug. 19, 2019

Introduction

An acceptable amount of compile time.

Dear reader, look at the screenshot in the title image. Now imagine instead of the test-compile phase taking the pictured amount of time, it instead took ~5 minutes. Now imagine solving this issue by simply swapping what assertion library was being used in your unit tests.

Wait really?

Yes.

The first attempt at fixing compilation times.

But why?

Being completely honest, we do not have the definitive answer to what was causing this, however, I do have a hunch.

We know that this became a big problem for us when we switched to Java 11. We also know that it didn’t matter if we were using Oracle JDK or OpenJDK as they are within a margin of error of one another. One of our team members, Kevin, discovered previously reported issues in JDK8 about a regression in compilation times, as well as him discovering other various issues and creating bug reports for javac.

Given this lack of polish with javac in Java 11 and knowing there were previous type inference issues that were probably exacerbated with the addition of the var keyword in Java 10, I figured that type inference had to be related to the issue, or at the very least the type system itself.

A big reason for us using AssertJ, in addition to handling exception better than JUnit4, is the fluent API that had made it a lot more ergonomic to use for developers. Code looked better, was easier to understand, and it made reuse easier.

If you are unfamiliar with the API of AssertJ, I have an example here:

    assertThat(myList).hasSize(n).containsAnyOf(matchObj)

You can imagine that assertThat not only being a heavily overloaded method and making use of generics, also allows you to branch out to many different similarly generic and heavily overloaded methods, that are context sensitive on the return type of the previous callable.

Another fact to consider is that javac is not sitting idle during this long compilation time, it is going full tilt on my machine maxing out the cores it is running on.

My hypothesis is that at some stage in javac, either type inference, or during the type erasure where it is bounding the generic types, that the root of the problem lies. It must be some computation of high complexity, maybe exponential based on the height of the type hierarchy for AssertJ.

Do I have this problem too?

One of the symptoms we noticed is that when opening a project and editing a file in IntelliJ Idea, the IDE would lint/inspect the file at a snail’s pace. For example, if I removed an important import and hit ctrl+s, for several seconds the IDE would slowly make its way through the file and I could see the red ticks on the scroll bar crawl it’s way down.

If this truly is related to complex type hierarchies and generics, I would love it if other people reached out and gave us examples outside of AssertJ, if for nothing more than building an understanding of what the root of the problem really is. I’d be just as happy if you were to debunk my hypothesis.

The lesson learned

As much as I enjoyed using AssertJ as my assertion library, productivity and the ability to deliver features must take precedence over ergonomics and code vanity.

While a 5 minutes compile time might not seem like the end of the world, we had other micro-services that were extremely well tested, and due to this issue, were causing our Jenkins server to take a half hour to build. And that dear reader, is not a fun time.

Dusan Andric, Team Lead
Software Architect and a full-stack software developer who enjoys tackling all manner of problems. Has a passion and history working in scientific and healthcare related fields. Will yell about the importance of testing. Loves dogs.