Unit Testing Using Junit 5

What is unit testing?

Unit testing is the first step(level) of testing in SDLC. In unit testing, a single unit or component of the software is tested by developers during the development phase or coding phase, and in this developers test the correctness of a particular component.

Why unit testing?

Unit testing is very important in software development, It ensures that every individual unit is giving the expected output.

  1. It helps in bug fixing at the initial level.
  2. It reduces minimal errors that may affect the production of software.

Test Driven Development:

As a developer we should be familiar with Test-Driven-Development.

Test-driven development (TDD) is a software development process that interweaves coding, testing, and design. It is a test-first approach that aims to improve the quality of your applications. Test-driven development is defined by the following lifecycle:

  1. Add a test.
  2. Run all of your tests and observe the new test failing.
  3. Implement the code.
  4. Run all of your tests and observe the new test succeeding.
  5. Refactor the code.

How to perform unit testing?

Junit 5 : 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

In this article, we will talk about unit testing in a spring boot application using Junit and Mockito tools.

First of all, we will create a maven-based spring boot application using spring initializer.

We will add basic dependency like spring boot and generate the project.

To perform unit testing using JUnit 5 we have to add the below dependencies to our project’s pom file.

We want to mock our classes so that we can test them in isolated environments, and here Mockito comes in picture. It mocks the actual class.

Here junit-jupiter is responsible for complete unit testing.

Here while creating project from spring initializer spring add these dependencies by default in our project. .

Now we will define some basic tests to understand the annotations and some basic terminologies of unit testing.

Output of the above test will be:

 

Here we used some annotations that are explained below:

  1. @SpringBootTest: We will define our test class with this annotation.
  2. @BeforeAll: This block of code will be executed on the startup of the test class.
  3. @BeforeEach: This block of code will be executed before every test case.
  4. @AfterAll: This block of code will be executed once all the test cases are executed.
  5. @AfterEach: This block of code will be executed after every test case.
  6. @Test: We use this to tell the compiler that this is our test case.
  7. @DisplayName: This annotation can be used with the test method to display its name in the runtime environment.
  8. @Mock: Use @Mock to create mocks which are needed to support testing of class to be tested.
  9. @InjectMock: Use InjectMocks to create class instances which needs to be tested in test class.

To test these services we will define our test methods with @Test annotation.

Note that @Test annotation comes from org.junit.jupiter.api package in JUnit 5.

In Junit 5 there are several static methods for comparing actual and expected result in Assertions class.

Below are some of the methods that we will use in this tutorial:

  1. assertArrayEquals: compares the contents of an actual array to an expected array.
  2. assertEquals: compare an actual value to an expected value.
  3. assertNotEquals: compares two values to validate that they are not equal.
  4. assertTrue: validates that the provided value is true.
  5. assertFalse: validates that the provided value is false.
  6. assertLinesMatch: compares two lists of Strings.
  7. assertNull: validates that the provided value is null.
  8. assertNotNull: validates that the provided value is not null.
  9. assertSame: validates that two values reference the same object.
  10. assertNotSame: validates that two values do not reference the same object.
  11. assertThrows: validates that the execution of a method throws an expected exception.
  12. assertTimeout: validates that a supplied function completes within a specified timeout.
  13. assertTimeoutPreemptively: validates that a supplied function completes within a specified timeout, but once the timeout is reached it kills the function’s execution.
  14. verify: Verifies certain behavior happened once.happened once.

Let’s take an example of a calculator  to understand the use of these annotations:

Controller Class:

Now we will define test cases for above class:

 

Here is the explaination of above test class:

  1. In this test class we are mocking the calculator service class by thinking that the service class will work correctly as expected and if we want to test the service class also then we need to implement the unit test on that method also.
  2. Then we inject that mock object in the class we are doing unit testing.
  3. Here as we can see in the controller that we are throwing an exception when both the inputs are zero so while testing we will get an exception in the result. So for that, we use try catch block.
  4. We are using verify directive to verify whether the request to add a method of calculator service is sent or not.
  5. Because initially we mocked the class with dummy data.So now if we want to access any method from the mocked class then we have to tell the mockito what to return, so for this we used when with thenReturn method which simply means when this method will be called then it have to return this value.
  6. We can also use doReturn with when for the same purpose.
  7. Here the 2nd test case failed because the calser.add method was not invoked for input 1,1 because we are not calling the calser.add method. So this test case meant to be failed.

 

Now we will implement unit testing on a real world example :

  1. Here we are using Spring in memory H2 database to save the data in the database.
  2. The Employee class has 3 fields named : id,name and salary.
  3. Here we are saving the employee details in the database and get those details from the database.
  4. Here we are creating unit cases for this example. 

Model class of project:

Response Class for controller:

Controller Class:

Here we created 3 endpoints to add Employee details, get particular employee object and get a list of all the employees from the database.

Now we will define employee service to implement all the logics.

Now we will define our Tests:

Testing using Junit’s doReturn-when method:

 

Here we simply tested our services of saving a player to db, get details of a  particular employee from db and getting all employees details. Here we used simple mockito’s methods to test these services. Following are the basic methods that we used in testing:

doReturn-when method: doReturn(employee).when(dao).save(any())

Here “employee” is the object that will be return when “save” method of dao is called. Here “dao” is the repository of entity “employee”. 

@DisplayName(“Test save Employee”): It will be shown in our console as the name of the test.

We successfully tested our services now we will move forward to test our controllers. 

Testing rest api endpoints using mockMvc:

Here we tested our controllers(api endpoints) using mockito’s mockMvc feature:

@AutoConfigureMockMvc: It automatically configures mockMvc for our unit testing. If we don’t want to use this annotation we can setup mockMvc manually by following method:

Explaination of Above Code in simple language:

  1. It will set up mockMvc as standAloneSetup before any test case execution.There are multiple types of setup that can be used under different conditions.
  2. We have to call mockMvc’s perform method to perform request like get, post ,put or delete.
  3. We have passed our api endpoint in get() method and we can pass our result expectation in andExpect method’s argument. Here we defined that the status of the result should be 200 ok which can be changed by the ResponseEntity object and can check for that status. If the status is not as expected then the test case will be failed.
  4. We can define what should be our content type of result.
  5. Here the “$” sign represents the resultant json object, hence here we returned two employees objects in result so we can check its size and values using keys. Here $[0] represents the first object in the json response. 
  6. In post method testing everything is the same as the get method except that in this case we passed our content as arguments in the content() method that should be passed in the request body.

Here we completed our unit testing in different scenarios and now we are ready to implement it in a live project, So all the best guys.

You can find complete source code under this link

If you find any difficulty in understanding code or any concept feel free to reach out in the comment section.

Thanks for all your love and support.

Comments