arrow left
Back to Developer Education

Getting Started With Unit Testing With Spring Boot

Getting Started With Unit Testing With Spring Boot

Writing decent unit tests is a skill that takes a long time to perfect. Unit testing is one of the ways that developers ensure that individual units or components work correctly. <!--more--> Before any code is deployed, it is subjected to unit testing to fulfill quality standards. Unit testing ensures that Spring Boot applications and their components are working as expected.

Prerequisites

For this tutorial, the reader would need:

  • Basic knowledge of Java programming
  • Basic knowledge of Spring Boot
  • An IDE installed. For this tutorial, we will use IntelliJ IDEA Ultimate.

Getting started

Before starting with the unit testing, let's first understand why it's important:

Advantages of unit testing

  • Unit testing allows developers to locate and fix bugs earlier.

  • It facilitates high-quality code. By running the test several times, developers gain confidence when changing the code.

  • Unit testing can boost a person's coding skills. Through this process, developers can learn how to write better code.

Best practices for unit testing

Below are some of the best practices when writing unit testing:

Separate the functionality that needs to be evaluated.

The functionality to be tested should be isolated by restricting the context in which loaded components are used. This is achieved by using the @Test annotation.

The advantage of this approach is that it is easy to locate tricky bugs and thus, promote clean production.

This particular feature, if used wisely, can help developers test large applications without impacting performance negatively.

Loading functionality in slices

It is crucial to restrict the application context to only the Spring components included in the test scenario. This is achieved by including them in the annotation declaration.

Use the @DataJpaTest Annotation

To increase the performance of different components, we use the @DataJpaTest annotation.

This is because it will not load beans annotated with@Service, @Controller, and the entire application context.

It's good to simulate database-interacting beans and disable Spring Boot test DB initialization for the Spring profile where the tests are executed.

You should always keep this practice in mind when testing controllers.

Make your test simple

Whenever senior developers teach unit testing to beginners, they should always ensure that the tests are straightforward.

To achieve this, developers should keep the test with low cyclomatic complexity. Cyclomatic complexity is a coding statistic that shows how many different execution pathways a procedure can take.

Developers are less likely to introduce problems when working on code with a lesser complexity since it is easier to understand and maintain.

Reasons for testing

Repositories

The repository is a bridge between the application and the database. It is tested to ensure that relationships between the database and the applications have been correctly implemented.

Services

This is the layer where the business logic is implemented. It is tested to ensure that the business logic is correct.

How to test controllers

Let us now look at how to test controllers in Spring Boot. To accomplish this, you will need to import some dependencies using the Spring Initializer and IntelliJ IDEA Ultimate.

In IntelliJ IDEA Ultimate, let's create a Spring Boot application using the Spring Initializr service.

Open file>new>project and select Spring Initializr as shown below:

Note: If you're not using IntelliJ IDEA Ultimate, you'll need to go to the Spring Initializer and add the Spring Web dependency to your project. Generate the zipped file and then open it using your favorite IDE.

Spring Initializer

Note: I have renamed my Package name to unittesting.

Click next to proceed. Type web to search the required dependencies in the search bar. Select Spring Web and click finish to download the initializr template:

Spring Initializer

We've prepared the environment successfully.🔥 Now we need to test the controller. In /src/main/java/unittesting create a new package named controller.

Proceed to create a Java class named HelloContoller.java in /src/main/java/unittesting/controller. Within that file, add the code below:

package unittesting.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(@RequestParam(name = "name", defaultValue = "Hello world") String name){
        return name;
    }
}

Let's look at the code snippet above:

  • @GetMapping is an annotation used to map the request to the method.
  • @RequestParam is an annotation used to map the request parameter to the method parameter.
  • @RestController is an annotation used to indicate that the class is a controller.

The next step is to generate the controller test. In the HelloController.java file, right-click and select Generate..>Test.. in the menu.

Select the available method (which we want to test) under the member and click ok.

Spring Initializer

A new file /src/test/java/unittesting/controller/HelloControllerTest.java will be created. Modify the file to have the code below:

package unittesting.controller;
import org.junit.jupiter.api.Test;
// import all the static methods from the Assertions class, so we may use them in this class
import static org.junit.jupiter.api.Assertions.*;

class HelloControllerTest {
    @Test
    void hello() {
        HelloController controller = new HelloController(); // instance of the controller
        String response = controller.hello("Hello world"); // act
        assertEquals("Hello world", response); // assert
    }
}

So far, we have created a test without including the Spring context. We should now generate another test using the JUnit 5 extension. It will have Spring extensions provided by Spring.

Repeat the same procedure to generate another test. Name the second test class HelloControllerIntTest.java. In /src/test/java/controller/HelloControllerIntTest.java, modify the code, as shown below:

package unittesting.controller;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@ExtendWith({SpringExtension.class})
@WebMvcTest(HelloController.class)
class HelloControllerIntTest {
    @Autowired
    private MockMvc mvc;
    @Test
    void hello() throws Exception {
        RequestBuilder request = MockMvcRequestBuilders.get("/hello");
        MvcResult result = mvc.perform(request).andReturn();
        assertEquals("Hello world", result.getResponse().getContentAsString());
    }
}

In the code snippet above:

  • @ExtendWith is an annotation used to extend the test with the SpringExtension.
  • @WebMvcTest auto-configures the MockMVC (so we can auto-wire it as demonstrated in the code above). We specify the class we want to test.

Let's test the controller to be sure it works correctly.

In the HelloControllerTest.java file, right-click and run HelloControllerTest. You should see the test passes, as shown below:

Test output

Conclusion

Congratulations! You have successfully tested the controller. There are various ways to create unit tests in Spring Boot. In this tutorial, we have learned how to conduct tests using MockMV.


Peer Review Contributions by: John Amiscaray

Published on: May 3, 2022
Updated on: Jul 15, 2024
CTA

Start your journey with Cloudzilla

With Cloudzilla, apps freely roam across a global cloud with unbeatable simplicity and cost efficiency