RU | EN | DE

1. Types of Tests

  1. Unit tests → check individual classes (fast, isolated).
  2. Integration tests → check component interaction (e.g., service + DB).
  3. End-to-End (E2E) → check the API as a whole (through MockMvc/TestRestTemplate).

2. Unit Tests (JUnit 5)

📄 Dependency (usually already present in spring-boot-starter-test):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

📄 Example:

class Calculator {
    int sum(int a, int b) { return a + b; }
}
class CalculatorTest {
    Calculator calc = new Calculator();
    @Test
    void testSum() {
        assertEquals(5, calc.sum(2, 3));
    }
}

3. Mockito (mocks and stubs)

📄 Example:

@Service
class UserService {
    private final UserRepository repo;
    public UserService(UserRepository repo) { this.repo = repo; }
    User getById(Long id) { return repo.findById(id).orElseThrow(); }
}
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    @Mock UserRepository repo;
    @InjectMocks UserService service;
    @Test
    void testGetById() {
        User u = new User(); u.setName("Vitaliy");
        when(repo.findById(1L)).thenReturn(Optional.of(u));
        User result = service.getById(1L);
        assertEquals("Vitaliy", result.getName());
    }
}

4. Spring Boot Integration Test

📄 Example:

@SpringBootTest
class UserServiceIntegrationTest {
    @Autowired UserRepository repo;
    @Autowired UserService service;
    @Test
    void testCreateUser() {
        User u = new User();
        u.setName("Test");
        service.createUser(u);
        assertThat(repo.findByName("Test")).isNotEmpty();
    }
}

📌 The @SpringBootTest annotation loads the entire Spring context (slower, but closest to reality).

5. MockMvc (testing REST API)

📄 Example:

@WebMvcTest(UserController.class)
class UserControllerTest {
    @Autowired private MockMvc mockMvc;
    @MockBean private UserService service;
    @Test
    void testGetUsers() throws Exception {
        when(service.allUsers()).thenReturn(List.of(new UserDto(1L, "Vitaliy")));
        mockMvc.perform(get("/api/users"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$[0].name").value("Vitaliy"));
    }
}

📌 @WebMvcTest loads only the web layer (without the DB). @MockBean replaces the service with a mock.

6. TestRestTemplate (integration API tests)

📄 Example:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserApiTest {
    @Autowired TestRestTemplate restTemplate;
    @Test
    void testCreateUser() {
        UserDto dto = new UserDto(null, "Vitaliy");
        ResponseEntity<UserDto> response =
            restTemplate.postForEntity("/api/users", dto, UserDto.class);
        assertEquals(HttpStatus.OK, response.getStatusCode());
        assertEquals("Vitaliy", response.getBody().name());
    }
}

7. Testcontainers (with a real DB)

📄 Example:

@SpringBootTest
@Testcontainers
class UserRepositoryTest {
    @Container
    static PostgreSQLContainer<?> postgres =
        new PostgreSQLContainer<>("postgres:15")
            .withDatabaseName("demo")
            .withUsername("demo")
            .withPassword("secret");
@DynamicPropertySource
static void props(DynamicPropertyRegistry reg) {
    reg.add("spring.datasource.url", postgres::getJdbcUrl);
    reg.add("spring.datasource.username", postgres::getUsername);
    reg.add("spring.datasource.password", postgres::getPassword);
}
 
    @Autowired UserRepository repo;
    @Test
    void testSaveUser() {
        User u = new User();
        u.setName("Vitaliy");
        repo.save(u);
        assertThat(repo.findByName("Vitaliy")).isNotEmpty();
    }
}

📌 These are the most realistic integration tests.

8. H2 (In-memory DB)

Quick replacement for dev/test. 📄 Setup:

spring:
  datasource:
    url: jdbc:h2:mem:testdb
    driver-class-name: org.h2.Driver
    username: sa
    password: password
  h2:
    console:
      enabled: true

📌 Open H2 console: http://localhost:8080/h2-console

9. Test Utilities

  • @DataJpaTest → tests only the JPA layer.
  • @JsonTest → tests Jackson serialization/deserialization.
  • @WebMvcTest → only controllers.
  • @SpringBootTest → entire context.

10. Best Practices

  • ✅ Write unit tests for business logic.
  • ✅ Integration tests → for DB and API.
  • ✅ Use MockMvc for REST, don’t load the entire server.
  • ✅ For complex cases → Testcontainers (real DB in Docker).
  • ✅ Tests should be fast and isolated.
  • ✅ Test levels:
    • Unit → cheap and fast,
    • Integration → more expensive,
    • E2E → only for critical scenarios.