Testing Spring Boot Applications: Unit, Integration, and Mocking — A Comprehensive Guide

Testing is a critical aspect of software development, ensuring the reliability and stability of your applications. In this blog post, we’ll dive into the essentials of testing Spring Boot applications using JUnit and Mockito. We’ll cover unit tests, integration tests, and mocking, providing examples using MockServer and Testcontainers.

What is Spring Boot?

Spring Boot is an open-source framework designed to simplify the development of Java applications. It provides a comprehensive infrastructure for developing microservices and standalone applications with minimal configuration. Spring Boot comes with embedded servers, making it easy to create and deploy applications quickly.

What is a Unit Test?

A unit test is a type of software testing where individual units or components of a software are tested in isolation from the rest of the application. The goal is to ensure that each unit of the software performs as expected. Unit tests are usually automated and help identify issues early in the development process.

Example of a Unit Test in Spring Boot

@SpringBootTest
@RunWith(SpringRunner.class)
public class MyServiceTest {

    @Autowired
    private MyService myService;

    @Test
    public void testCalculateSum() {
        int result = myService.calculateSum(5, 10);
        assertEquals(15, result);

        /*
          myService.calculateSum() doesn't have external 
          integration/dependencies, this way we're testing the 
          unit calculateSum() and only that, making this test a Unit Test
        */
    }
}

What is an Integration Test?

An integration test is a type of testing where individual units are combined and tested as a group. The purpose is to verify the interactions between different parts of the application and ensure they work together correctly. Integration tests often involve external components like databases, message brokers, and web services.

Example of an Integration Test in Spring Boot

@SpringBootTest
@AutoConfigureMockMvc
@RunWith(SpringRunner.class)
public class MyControllerIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testGetEndpoint() throws Exception {
        mockMvc.perform(get("/api/data"))
                .andExpect(status().isOk())
                .andExpect(content().string("Hello, World!"));
                
        /*
          this way we're testing the entire flow 
          (with all the external integrations and dependencies 
          the route /api/data may have, making this a Integration Test
        */
    }
}

What is JUnit?

JUnit is a popular testing framework for Java, used to write and run repeatable tests. It provides annotations to identify test methods, setup and teardown routines, and assertions to check expected results.

What is Mocking and Mockito?

Mocking is a technique used in unit testing to simulate the behavior of real objects. This allows you to test components in isolation without relying on external dependencies. Mockito is a popular mocking framework for Java, making it easy to create and configure mock objects.

Example of Mocking with Mockito

@RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {

    @InjectMocks
    private MyService myService;

    @Mock
    private MyRepository myRepository;

    @Test
    public void testFindById() {
        when(myRepository.findById(1L)).thenReturn(Optional.of(new MyEntity(1L, "Test")));
        MyEntity result = myService.findById(1L);
        assertEquals("Test", result.getName());
        
        // this way we're mocking the repository layer, making the test still unit, even with an external dependency
    }
}

Using MockServer and Testcontainers

MockServer and Testcontainers are powerful tools for creating integration tests that involve external services.

Example of MockServer

MockServer allows you to mock HTTP requests and responses.

@SpringBootTest
@RunWith(SpringRunner.class)
public class MyServiceIntegrationTest {

    private ClientAndServer mockServer;

    @Before
    public void startServer() {
        mockServer = ClientAndServer.startClientAndServer(1080);
    }

    @After
    public void stopServer() {
        mockServer.stop();
    }

    @Test
    public void testExternalServiceCall() {
        mockServer.when(
                request()
                        .withMethod("GET")
                        .withPath("/external-api"))
                .respond(
                        response()
                                .withStatusCode(200)
                                .withBody("Mocked Response"));
        String result = myService.callExternalService();
        assertEquals("Mocked Response", result);
    }
}

Example of Testcontainers

Testcontainers provides lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.





Conclusion

Testing Spring Boot applications effectively requires understanding and implementing various types of tests, such as unit tests, integration tests, and mocking. JUnit and Mockito are essential tools in this process, and frameworks like MockServer and Testcontainers can significantly enhance your testing capabilities. By incorporating these practices, you can ensure your Spring Boot applications are robust, reliable, and maintainable.