How to start with unit testing in Java: A complete introduction to JUnit 5
Tags: java, beginners, testing
Published: 2019-03-12 07:03:58

---
title: How to start with unit testing in Java: A complete introduction to JUnit 5
published: true
description: 
tags: java, beginners, testing
cover_image: https://www.mednikov.net/wp-content/uploads/2019/02/pexels-photo-250659.jpeg
canonical_url: https://mednikov.net/write-unit-tests-with-junit5-platform/
---

Hello Dev.to! In this post, I would like to focus on unit testing in Java with JUnit5 library. It introduced new features and approaches to testing, compare to older JUnit 4 version, that are worth to check. We would overview what is unit test and why to test; how to install JUnit 5 in your project; what is a basic test structure; how to use Asseritions API and how to combine multiple tests in a test suite.

Btw, original post was published in my blog and you [can find it here](https://www.mednikov.net/tutorials/how-to-start-with-unit-testing-in-java-a-quick-introduction-to-junit-5/)

## What is unit testing? 

_Unit testing_ is a level of software testing, when we test individual software's components in isolation. For example, we have __UserService__. It may have various connected dependencies, like __UserDAO__ to connect to a datasource, or __EmailProvider__ to send confirmation emails. But for unit testing, we isolate __UserService__ and may _mock_ connected dependencies (how to do mocking, we would see in the next chapter).

The unit testing offers us a number of benefits, to name few:

- It increases our confidence, when we change code. If unit tests are good written and if they are run every time any code is changed, we can notice any failures, when we introduce new features
- It serves as documentation. Certanly, documenting your code includes several instruments, and unit testing is one of them - it describes an _expected_ behaviour of your code to other developers.
- It makes your code more _reusable_, as for good unit tests, code components __should be__ modular.

These advantages are just few of numerous, that are provided us by unit testing. Now, when we defined what is unit testing and why do we use it, we are ready to move to JUnit5.

## Install JUnit5

### Build tools support

For a native support of JUnit5 you should have a version of Gradle 4.6+ or Maven 2.22.0+.

For Maven you need to add to your _Pom.xml_:

```xml
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>{$version}</version>
    <scope>test</scope>
</dependency>
```

For Gradle add to _build.gradle_:

```groovy
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '$version'
```

You could find the latest version of JUnit5 in [the official repository](https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api). By the way, if you would use JUnit 5 with Vert.x framework, there is [Vert.x JUnit5 extension](https://www.mednikov.net/tutorials/start-with-vertx-junit5-at-no-time/).

### IDE support

Intelij IDEA supports JUnit5 natively since 2016.2, and Eclipse since 4.7.1a. 

## An anatomy of unit test

### Basic structure

Consider this example: we have a program, that performs a [_linear search_](https://www.geeksforgeeks.org/linear-search/) of a number in an array of integers. Here is a main class, that we place in the _src/main/java/_ folder:

```java
class LinearSearcher(){

	private int[] data;
   
   LinearSearcher(int[] arr){
      this.data = arr;
   }
   
   int getPositionOfNumber(int value){
      int n = data.length; 
      for(int p = 0; i < n; i++) 
         { 
           if(data[p] == value) 
            return p; 
          } 
      return -1; 
   }
}

```

And then add this second code to the _src/test/java_ folder: 

```
class LinearSearcherTest{

    private static LinearSearcher searcher;

    //before
    @BeforeAll
    static void setup(){
       int[] array = {2, 3, 4, 10, 40};
       searcher = new LinearSearcher(array);
    }
    
    //Actual test methods
    @Test
    void getPosition(){
       int result = searcher.getPositionOfNumber(10);
       Assertions.assertEquals(3,result);
    }

    @Test
    void noSuchNumber(){
       int result = searcher.getPositionOfNumber(55);
       Assertions.assertEquals(-1, result);
    }
    
    //after
    @AfterAll
    static void finish(){
       System.out.println("Tests are finished!");
    }
}
```

Let check what we did in this code. We introduced a new class, _LinearSearcher_ that has one method - _getPostionOfNumber_ that returns the position of value in the array, or returns -1, if value is not presented in the array.

In second class, _LinearSearcherTest_ we actually do unit testing. We expect two scenarios: when we have a number in the array (in our case 10), we expect to receive its position (3). If no such number is presented (for example 55), our searcher should return -1. Now, you can run this code and check results.

### Before methods

You could note two methods annotated respectively with _@BeforeAll_ and _@AfterAll_. What do they do? First method corresponds to __Before methods__. There are two of them:

- @BeforeAll - the __static__ method that will be executed once before __all__ @Test method in the current class.
- @BeforeEach - the method that will be executed before __each__ @Test method in the current class.

These methods are handy to setup unit test environment (for example, to create instances).

### After methods

As there are _before methods_, there are __After methods__. There is also a couple of them:

- @AfterAll - the __static__ method will be executed once after __all__ @Test methods in the current class.
- @AfterEach - the method that will be executed after __each__ @Test method in the current class.

## Using standard Assertions API

_Assertions API_ is a collection of utility methods that support asserting conditions in tests. There are numerous available methods, however we would focus on most important of them.

### Assert not null

When we need to assert, that _actual object_ is not null, we can use this method:

```java
assertNotNull(Object obj);
```

If object is not null, the method passes, if not - fails.

### Assert Equals

This group includes many methods, so I would not provide your [all overloaded versions](https://junit.org/junit5/docs/5.0.1/api/org/junit/jupiter/api/Assertions.html#assertEquals-byte-byte-), but would focus a general signature:

```java
assertEquals(expected_value, actual_value, optional_message);
```

These methods have two _required arguments_ and one _optional argument_:

- expected_value = the result, we want to receive 
- actual_value = the tested value
- optional_ message = String message, that would be displayed to STDOUT if method is failed.

Values can be of primitive types: int, double, float, long, short, boolean, char, byte, as well Strings and Objects. To this group, we can add these test methods:

- __assertArrayEquals__ - check that expected and actual arrays are equal. Arrays are of primitive types
- __AssertFalse__ and __AssertTrue__ -  check that supplied boolean condition is false or true respectively
- __assertIterableEquals__ - same as assertArrayEquals, but for [Iterables](https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html) (e.g. List, Set etc)

As I mentioned, there are many overloaded methods in this section, so it worth to explore [official documentation](https://junit.org/junit5/docs/5.0.1/api/org/junit/jupiter/api/Assertions.html) for concrete signatures.

### Assert throws

This is an innovation of JUnit5. Consider, that you have a method that throws an exception:

```java
Car findCarById(String id) throws FailedProviderException;
```

This method retrieves an individual _Car_ from an underlaying database by its ID, and throws FailedProviderException when there is a problem with database. In other words, we wrap in an interface possible data source exceptions (like SQLException or respected for NoSQL databases) and achieve its independence from the implementation.

How do we test that exception is thrown? Before, in JUnit4 we used annotations:

```java
@Test(expected = FailedProviderException.class)
void exceptionThrownTest() throws Exception{
    Car result = repository.findCarById("non-existing-id");
}
```

Btw, same idea is used in TestNG. In JUnit5 was introduced _assertThrows_ method. Take a look, how we would deal with same situation:

```java
@Test
void exceptionThrownTest(){
    Assertions.assertThrows(FailedProviderException.class, ()->{
        Car result = repository.findCarById("non-existing-id");
    });
}
```

This method signature has two components:

1. Expected exception to be thrown
2. Lambda expression of [_Executable_](https://junit.org/junit5/docs/5.0.1/api/org/junit/jupiter/api/function/Executable.html), that contains a code snippet, that potentially throws the exception.

Again, as we aforesaid methods of assertEquals's group, we can provide an optional message of String as third argument.

### Assert timeout

When we need to assert, that test is finished in a defined timeout, we can use this method:

```java
assertTimeout(Duration timeout, Executable executable)
```

The idea is same as with assertThrows method, but there we specify _timeout_. Second argument is a same Executable lambda expression. Third optional component is a String message. Let consider an example:

```java
@Test
void in3secondsTest(){
   Assertions.assertTimeout(Duration.ofSeconds(3), ()->{
      //some code
   });
}
```

Please note, that this method uses _Duration API_ to specify timeframe. It has several handy methods, like ofSeconds(), ofMills() etc. If you are not familiar with it, [don't be shy to check this tutorial](https://docs.oracle.com/javase/tutorial/datetime/iso/period.html).

### Fail

Finally, what if we need to fail test? Just use _Assertions.fail()_ method. Again, there are several of them:

- fail (String message) = Fails a test with the given failure message.
- fail (String message, Throwable cause) = Fails a test with the given failure message as well as the underlying cause.
- fail (Throwable cause) = Fails a test with the given underlying cause.

## Creating test suites

If you have several unit tests and you want to execute them in one load, you can create a _test suite_. 

This approach allows you to run tests spread into multiple test classes and different packages. 

Suppose, that we have tests TestA, TestB, TestC, that divided into three packages: net.mednikov.teststutorial.groupA, net.mednikov.teststutorial.groupA, net.mednikov.teststutorial.groupC respectively. We can write the test suite to combine them:

```java
@RunWith(JUnitPlatform.class)
@SelectPackages({net.mednikov.teststutorial.groupA, net.mednikov.teststutorial.groupB, net.mednikov.teststutorial.groupC})
public class TestSuite(){}
```

Now, you can run this method as one test suite.

## References

- Sergio Martin. _Take Unit Testing to the Next Level With JUnit 5_ (2018). DZone, [read here](https://dzone.com/articles/take-unit-testing-to-the-next-level-with-junit-5)
- Petri Kainulainen. _Writing Assertions with JUnit5 Assertion API_ (2018), [read here](https://www.petrikainulainen.net/programming/testing/junit-5-tutorial-writing-assertions-with-junit-5-api/)
- J Steven Perry. _The JUnit5 Jupiter API_ (2017) IBM Developer, [read here](https://developer.ibm.com/tutorials/j-introducing-junit5-part1-jupiter-api/)

## Conclusion

In this post, we learned what is unit test and why to test; how to install JUnit 5 in your project; what is a basic test structure; how to use Asseritions API and how to combine multiple tests from different packages in a test suite. But, of course, JUnit 5 is a huge topic, and this post is just a top of an iceberg. Some frameworks, like Vert.x, offer special JUnit 5 extensions, like [vertx-junit5](https://www.mednikov.net/tutorials/start-with-vertx-junit5-at-no-time/). Good luck with JUnit5 ! :)