Why You Should Start Using JUnit 5
Tags: java, junit, testing
Published: 2018-08-05 14:19:00

---
title: Why You Should Start Using JUnit 5
published: true
description: My favorite features of JUnit 5
tags: java,junit,testing
cover_image: https://thepracticaldev.s3.amazonaws.com/i/m8472hypclwrc2ee7ggo.png
---
*This is a cross-posting of an article published on my blog which you can find [here](https://return.co.de/blog/articles/why-you-should-start-using-junit-5/).*

What is JUnit 5? 

According to its [website](https://junit.org/junit5/),

> JUnit 5 is the next generation of JUnit. The goal is to create an up-to-date foundation for developer-side testing on the JVM. This includes focusing on Java 8 and above, as well as enabling many different styles of testing.

This article is for everyone that did or did not hear about JUnit 5 and wonders why they would want to use it.

I don't want to go into details on all the features or how it works internally, I just want to show *some* of the new features that are most valuable to me so far.

So let's get right into it...

# Display Name

Previously in JUnit, tests got their names from their test methods.

E.g.:

```java
    public class AccountTest {
        
        @Test
        public void testMethod() {
            // do some tests here
        }
    }
```

When you run it, it will print out `testMethod` as the name for the test which is problably not very useful and most importantly not readable. Test shoud be human readable because tests are the only true code documentation that does not get deprecated. So people started trying to come up with some more descriptive test names.

```java
    public class AccountTest {
        
        @Test
        public void withdrawSomeAmountGreaterThanCurrentBalanceFailsWithException() {
            // do some tests here
        }
    }
```

Better? Not so much. At least it gives you some idea on what is going to happen here. Something about withdrawing some amount from an account that is greater than the current balance. That should fail. But how to make it more readable? Some developers (including myself) started breaking with the strict Java convention of camelCase and started using underlines to separate aspects of the test, for instance `method__scenario__expectedResult`.

```java
    public class AccountTest {
        
        @Test
        public void withdraw__amountGreaterThanCurrentBalance__failsWithException() {
            // do some tests here
        }
    }
```

This is a bit more readable although it hurts the eyes of every Java developer that is used to camelCase. What you actually want is using any arbitrary string as the test name. 

Kotlin allow you to use string literals like e.g.

```kotlin
    internal class AccountTest {
        
        @Test
        fun `should thrown an exception when an amount is withdrawn greater that the current balance`() {
            // do some tests here
        }
```

JUnit 5 to the rescue. Although not as simple as in Kotlin, JUnit 5 comes with an `@DisplayName` annotation that can be used for both test classes and methods. The downside is, you still need to make a method name: 

```java
    @DisplayName("An account")
    class AccountTest {
        
        @Test
        @DisplayName("should throw an exception when an amount is withdrawn greater that the current balance")
        void withdrawBalanceExceeded() {
            // do some tests here
        }
    }
```

So although its the typical Java annotation cluttering going on, the result (as in what the IDE shows) is much more readable.

*Note that you do not need to use `public` anymore with methods and classes.*

# Nested Tests

While pair-programming with a colleague, I was copy and pasting tests and descriptions and just change parts of it to tests different edge cases. She told me I should use nested tests. We tried it and I immediately fell in love with the idea.
Instead of having test like this:

- An account
    - should throw an exception when an amount is withdrawn greater that the current balance
    - should reduce the balance by the amount that is withdrawn

You could do something like that

- An account
    - withdrawal
        - should throw an exception when the amount greater that the current balance
        - should reduce the balance by the amount

With JUnit 5, it looks like this:

```java
    @DisplayName("An account")
    public class AccountTest {
        
        @Nested
        @DisplayName("withdrawal")
        class Withdrawal {
            
            @Test
            @DisplayName("should throw an exception when the amount greater that the current balance")
            public void failureBalanceExceeded() {
                // do some tests here
            }
    
            @Test
            @DisplayName("should reduce the balance by the amount")
            public void success() {
                // do some tests here
            }
        }
    }
```

Again, the gross number of lines increase by using `@Nested` as it is necessary to wrap tests within a nested class but it keeps the tests its self cleaner.

# Extensions

JUnit 5 is built to be very extensible. Custom or third-party extensions can be added by using the `@ExtendWith` annotation at class level.

## Spring Boot

Spring boot integration tests for example are now run by using `@ExtendWith(SpringExtension.class)`. Note that this only works from spring-boot 2.x and higher.

## Mockito Extension

There will be an updated `MockitoExtension` that could do something like that:

```java
    @ExtendWith(MockitoExtension.class)
    class MyMockitoTest {
    
        @BeforeEach
        void init(@Mock Person person) {
            when(person.getName()).thenReturn("Dilbert");
        }
    
        @Test
        void simpleTestWithInjectedMock(@Mock Person person) {
            assertEquals("Dilbert", person.getName());
        }
    }
```

So you do neither need to write `Person person = mock(Person.class)` or use `@Mock private Person person`.

# Migration from 4 to 5

Those new features in JUnit 5 come at a price: They are not compatible with JUnit 4 tests. This is called JUnit Jupiter.

"But wait, what about my existing 500 test cases suite?" you might ask. It not as bad as you might think. The JUnit team did a smart thing, they moved all JUnit Jupiter code and annotations in a separate package so can have both JUnit 4 and 5 in the same code base. You would still need to add the new JUnit platform, the JUnit 4 tests are called JUnit Vintage. There is a nice article about the migration you can find [here](http://www.baeldung.com/junit-5-migration).

We actually have a project with hundreds of tests and we step-by-step migrate them. All new tests are written with JUnit 5 and once we need to touch existing tests, we migrate them. It basically delete all JUnit `import`s, and replace `@Before` by `@BeforeEach` as well as `@BeforeClass` by `@BeforeAll`.

# Conclusion

Although Java itself could be improved a lot by e.g. introducing meta programming (which has its disadvantages, too) or at least allow string literals as method names to make tests even more readable, but JUnit 5 is way better than JUnit 4 and I would assume that there will be a lot of extensions to come in the future.

Moreover, there are a lot of improvements to JUnits assertion library but since I use [AssertJ](https://joel-costigliola.github.io/assertj/), I didn't cover that part. See the JUnit 5 documentation for reference.