Unit Testing Using Junit5 in SpringBoot
Overview
For any software system, three kinds of automated test cases are traditionally written based on the scope and how much functionality they cover.
- Unit tests
- Integration tests
- End-to-end tests
The scope of the test can be well understood from the test pyramid.
The test pyramid is a way of thinking about how different automated tests should be used to create a balanced portfolio. Its essential point is that you should have many more low-level Unit Tests, fewer integration tests, and even fewer end-to-end tests.
The higher we climb the pyramid, the more tests become more complicated and execute slower. The quality of the application is determined by the number of test cases it has and the code it covers.
Introduction to Unit Testing
Unit testing refers to a methodology in which we write code to check a unit's validity.
What is a Unit?
This can be a single method, a class, or multiple classes that can be tested without any network interaction. Unit tests should not make any network operation like calling database or external API.
Benefit of Unit Testing
- Detects bugs in the early stages of the Software Development Life Cycle (SDLC).
- Makes sure that the code works as expected.
- Provides confidence when refactoring the existing code.
- Helps new developers understand the current behavior of the system.
Introduction to Junit 5
JUnit is a popular Unit Testing Framework that helps Java developers unit test their code.
JUnit was originally developed by Kent Beck and Erich Gamma in 1997. JUnit 5 is the latest version of the software.
Architecture of Junit 5
JUnit 5 is composed of three modules; each has a different purpose.
- JUnit Jupiter - Jupiter provides an API for developers to write tests and extensions. It also provides a TestEngine API implementation to run these tests on the platform.
- JUnit Platform - The platform module provides an API based on the interface Launcher. Platform developers like IDEs and test frameworks use it to launch and run tests from their platforms.
- JUnit Vintage - The Vintage module provides a TestEngine implementation to support backward compatibility for tests written with JUnit 3 and 4.
First Unit Test Using JUnit 5
Maven Dependency
Setting up JUnit 5.x.0 is pretty straightforward; we need to add the following dependency:
We usually use test classes to interact with JUnit 5.
A test method has the following characteristics:
- It should have the org.junit.jupiter.api.Test annotation.
- It should return void.
- It may contain parameters.
AAA Pattern for Good Test Case
Unit testing is good, but how can we write good test cases?
There’s a simple and powerful pattern - Arrange-Act-Assert.
Arrange
In the arrange phase, we initialize the piece of the unit we want to test. We prepared data, prepared mock or login if the application is secure.
Act
Act steps should cover the method to be tested. In this step, we invoke the actual method.
Assert
We verify whether the method's behavior matches our expectations in the Assert phase.
Sample test with AAA pattern
Junit 5 Annotations
Annotation can be categorized into three categories Before the test, During the test(optional), and after the test.
Before the Test
-
@BeforeAll Executes exactly once before all test methods.
-
@BeforeEach Executes before each @Test method in this class.
After the Test
- @AfterEach Executes after each @Test method.
- @AfterAll Executes after all the @Test methods inside the class.
Junit 5 Assertions
Assertions are used to verify the behavior of our test. These methods are provided by the org.junit.jupiter.api.Assertions class.
Below are some popular methods provided by the Assertions class:
Assert Method | Purpose |
---|---|
assertEquals | Assert that expected and actual values are equal. |
assertNotEquals | Assert that expected and actual values are not equal. |
assertTrue | Assert that condition is true. |
assertFalse | Assert that condition is false. |
assertNull | Assert that object is null. |
assertNotNull | Assert that object is not null. |
assertSame | Assert that expected, and actual values refer to the same object. |
assertNotSame | Assert that expected, and actual values do not refer to the same object. |
assertArrayEquals | Assert that expected and actual arrays are equal. |
assertThrows | Assert that execution of the supplied code throws an exception. |
Testing Exception
Junit 5 provides the asserThrows assertion for testing the exception.
Parameterized Test
JUnit 5 allows a test to run multiple times with different arguments. They are declared normal tests, but we use the @ParameterizedTest annotation instead of the @Test annotation. This helps test our method with various input data.
The parameterized test uses @ValueSource to provide the input values to the test method. It accepts an array as input, and each element is passed as input to the test method.
Below is an example of this annotation:
The above test will run five times for each input supplied in the @ValueSource annotation.
JUnit Test Suites
Test suites are groups of test runs together. JUnit 5 provides two annotations, @SelectPackages and @SelectClasses, to create test suites.
The above code will run all test cases together under the com.scaler package.
Conclusion
This article covered
- What is a test pyramid.
- What is a unit test case and its benefits of it?
- AAA pattern for writing unit test case
- Junit 5 test case lifecycle