Logo

dev-resources.site

for different kinds of informations.

Spring Boot Testing Best Practices

Published at
6/23/2024
Categories
spring
springboot
junit
mockito
Author
abhishek999
Categories
4 categories in total
spring
open
springboot
open
junit
open
mockito
open
Author
11 person written this
abhishek999
open
Spring Boot Testing Best Practices

Testing is a crucial aspect of software development, ensuring that your application behaves as expected and is free from bugs. Spring Boot provides excellent support for testing, making it easier to write unit tests, integration tests, and test RESTful services. In this blog, we will explore best practices for testing Spring Boot applications, covering unit testing, integration testing, and using MockMvc for testing RESTful services

Writing Unit Tests for Spring Boot Applications
Unit tests are the foundation of a solid test suite. They focus on testing individual components in isolation, such as methods or classes, without depending on external systems like databases or web servers

Best Practices for Unit Testing:

Use JUnit 5: JUnit 5 is the latest version of the popular testing framework and provides powerful features for writing tests. Ensure you include the necessary dependencies in your pom.xml or build.gradle file


<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.8.1</version>
    <scope>test</scope>
</dependency>

Enter fullscreen mode Exit fullscreen mode

Mock Dependencies: Use mocking frameworks like Mockito to mock dependencies and focus on testing the logic of the class under test

@SpringBootTest
public class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void testFindUserById() {
        User user = new User(1L, "John");    

when(userRepository.findById(1L)).thenReturn(Optional.of(user));

        User result = userService.findUserById(1L);

        assertEquals("John", result.getName());
    }
}

Enter fullscreen mode Exit fullscreen mode

Test Boundary Conditions: Ensure you test edge cases, null values, and invalid inputs to make your tests comprehensive

Write Fast and Isolated Tests: Unit tests should run quickly and independently. Avoid using external resources like databases or file systems

Use Test Doubles for Dependencies: When necessary, create stub or mock implementations for dependencies that your class under test interacts with. This helps isolate the component being tested

@Test
void testUserCreation() {
    User user = new User(null, "Jane");
    when(userRepository.save(any(User.class))).thenReturn(new User(1L, "Jane"));

    User createdUser = userService.createUser(user);

    assertNotNull(createdUser.getId());
    assertEquals("Jane", createdUser.getName());
}

Enter fullscreen mode Exit fullscreen mode

Integration Testing with Spring Boot :
Integration tests verify that different parts of the application work together as expected. They test the application’s behavior in a realistic environment, including interactions with databases, web servers, and other systems

Best Practices for Integration Testing :

Use @SpringBootTest: The @SpringBootTest annotation loads the full application context and is useful for writing integration tests

@SpringBootTest
@ExtendWith(SpringExtension.class)
public class UserServiceIntegrationTest {

    @Autowired
    private UserService userService;

    @Autowired
    private UserRepository userRepository;

    @Test
    void testFindUserById() {
        User user = new User(1L, "John");
        userRepository.save(user);
        User result = userService.findUserById(1L);
        assertEquals("John", result.getName());
    }
}

Enter fullscreen mode Exit fullscreen mode

Use @Transactional for Database Tests: Use the @Transactional annotation to ensure that database changes are rolled back after each test, maintaining a clean state

@SpringBootTest
@Transactional
public class UserServiceIntegrationTest {
    // Integration tests
}
Enter fullscreen mode Exit fullscreen mode

Profile-Specific Configuration: Use different application properties for testing to avoid conflicts with development or production environments

# src/test/resources/application-test.yml
spring:
  datasource:
    url: jdbc:h2:mem:testdb
    driver-class-name: org.h2.Driver
    username: sa
    password: password

Enter fullscreen mode Exit fullscreen mode

Test Slices: Use test slices like @WebMvcTest, @DataJpaTest, @RestClientTest to load only the necessary parts of the application context, making tests faster and more focused

@DataJpaTest
public class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    void testSaveUser() {
        User user = new User(null, "Alice");
        User savedUser = userRepository.save(user);
        assertNotNull(savedUser.getId());
        assertEquals("Alice", savedUser.getName());
    }
}

Enter fullscreen mode Exit fullscreen mode

Using MockMvc for Testing RESTful Services
MockMvc is a powerful tool for testing Spring MVC controllers. It allows you to perform HTTP requests and assert responses without starting the entire web server

Best Practices for Using MockMvc

Setup MockMvc with @WebMvcTest: Use the @WebMvcTest annotation to test only the web layer and configure MockMvc

@WebMvcTest(UserController.class)
public class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    @Test
    void testGetUserById() throws Exception {
        User user = new User(1L, "John");
        when(userService.findUserById(1L)).thenReturn(user);

        mockMvc.perform(get("/users/1"))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.name").value("John"));
    }
}

Enter fullscreen mode Exit fullscreen mode

Test Different Scenarios: Ensure you test various scenarios, including success, failure, and edge cases

@Test
void testGetUserById_NotFound() throws Exception {
    when(userService.findUserById(1L)).thenThrow(new UserNotFoundException());

    mockMvc.perform(get("/users/1"))
           .andExpect(status().isNotFound());
}

Enter fullscreen mode Exit fullscreen mode

Use JSONPath for Response Assertions: Use JSONPath expressions to assert specific parts of the JSON response.

mockMvc.perform(get("/users/1"))
       .andExpect(status().isOk())
       .andExpect(jsonPath("$.id").value(1))
       .andExpect(jsonPath("$.name").value("John"));

Enter fullscreen mode Exit fullscreen mode

Verify Interactions: Use Mockito to verify that service methods are called as expected.

verify(userService).findUserById(1L);

Enter fullscreen mode Exit fullscreen mode

Test with Different HTTP Methods: Test various HTTP methods (GET, POST, PUT, DELETE) to ensure your RESTful services handle them correctly

@Test
void testCreateUser() throws Exception {
    User user = new User(null, "Jane");
    when(userService.createUser(any(User.class))).thenReturn(new User(1L, "Jane"));

    mockMvc.perform(post("/users")
            .contentType(MediaType.APPLICATION_JSON)
            .content("{\"name\": \"Jane\"}"))
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.id").value(1))
            .andExpect(jsonPath("$.name").value("Jane"));
}

Enter fullscreen mode Exit fullscreen mode

Test Error Handling: Ensure your tests cover error scenarios and that your application returns appropriate error responses

@Test
void testCreateUser_InvalidInput() throws Exception {
    mockMvc.perform(post("/users")
            .contentType(MediaType.APPLICATION_JSON)
            .content("{\"name\": \"\"}"))
            .andExpect(status().isBadRequest())
            .andExpect(jsonPath("$.errors").isNotEmpty());
}

Enter fullscreen mode Exit fullscreen mode

Conclusion
Testing is a vital part of developing reliable and maintainable Spring Boot applications. By following these best practices for unit testing, integration testing, and using MockMvc, you can ensure that your application is robust and behaves as expected. Remember to write tests that are fast, isolated, and comprehensive to cover various scenarios and edge cases

Happy testing!

junit Article's
30 articles in total
Favicon
verify() method in Mockito example
Favicon
Uses of @spy annotation in junit testing
Favicon
How To Install TestNG in Eclipse: Step By Step Guide
Favicon
How to simulate real BeforeAll and AfterAll in JUnit 5
Favicon
Spring Boot Testing Best Practices
Favicon
Why there are so many assertAll methods in Junit class AssertAll? What is the use of each.
Favicon
Testando das trincheiras: Como criar mocks e stubs dinâmico com mockito em java
Favicon
Mastering Selenium Testing: JUnit Asserts With Examples
Favicon
JUnit Tutorial: An Inclusive Guide [With Enhanced Features]
Favicon
Junit Badge For Git Project
Favicon
Testes Unitários com JUnit no Java
Favicon
JUnit 5 – When to use CSV Providers
Favicon
JUnit Tutorial: An Inclusive Guide [With Enhanced Features]
Favicon
Less Code, More Tests: Exploring Parameterized Tests in JUnit
Favicon
How to find bugs before sending it to production using boundary testing technique
Favicon
Test utilities, or set-up methods considered harmful
Favicon
Dominando o Poder dos Testes Unitários em Java com JUnit: Construa Código Sólido e Confiável! 🚀🧪🔨
Favicon
How to resolve the configuration problem with 2 application.properties in Springboot?
Favicon
TestNG vs JUnit: An Unbiased Comparison Between Both Testing Frameworks
Favicon
Quick introduction to EasyRandom
Favicon
JUnit Tests in Java: A Guide to Writing Effective Unit Tests
Favicon
JUnit's @CsvSource.quoteCharacter
Favicon
Creating a REST API using Spring Boot + Tests + Documentation [part 04]
Favicon
How to use Junit and Mockito for unit testing in Java
Favicon
Unit Testing JSON Functions in Android
Favicon
Adding Unit Testing to OpenSSG
Favicon
Running JMH benchmark from Eclipse
Favicon
Setting up Junit 5 Parallel Test Execution With Maven
Favicon
Integration Tests with Micronaut and Kotlin
Favicon
Spring Boot Integration Testing with MockMvc

Featured ones: