Tutorials Logic, IN +91 8092939553 info@tutorialslogic.com
FAQs Support
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Interview Questions Website Development
Compiler Tutorials

Spring Testing

Testing Annotations Overview

AnnotationDescriptionUse Case
@SpringBootTestLoads the full application contextIntegration tests
@WebMvcTestLoads only the web layer (controllers)Controller unit tests
@DataJpaTestLoads only JPA components, uses in-memory DBRepository tests
@MockBeanCreates a Mockito mock and adds it to the Spring contextMocking dependencies
@ExtendWith(SpringExtension.class)Integrates Spring with JUnit 5All Spring tests
Testing REST Controllers with @WebMvcTest and MockMvc
package com.example.controller;

import com.example.model.User;
import com.example.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import java.util.List;
import java.util.Optional;

import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

// @WebMvcTest loads only the web layer — fast, no DB needed
@WebMvcTest(UserController.class)
class UserControllerTest {

    @Autowired
    private MockMvc mockMvc; // Simulates HTTP requests without starting a server

    @MockBean
    private UserService userService; // Replaces real UserService with a Mockito mock

    @Test
    void getAllUsers_shouldReturn200WithUserList() throws Exception {
        // Arrange: define mock behavior
        when(userService.findAll()).thenReturn(
            List.of(new User(1L, "Alice", "alice@example.com"),
                    new User(2L, "Bob",   "bob@example.com"))
        );

        // Act & Assert: perform GET and verify response
        mockMvc.perform(get("/api/users")
                .accept(MediaType.APPLICATION_JSON))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.length()").value(2))
               .andExpect(jsonPath("$[0].name").value("Alice"))
               .andExpect(jsonPath("$[1].email").value("bob@example.com"));

        verify(userService, times(1)).findAll();
    }

    @Test
    void getUserById_whenNotFound_shouldReturn404() throws Exception {
        when(userService.findById(99L)).thenReturn(Optional.empty());

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

    @Test
    void createUser_withValidData_shouldReturn201() throws Exception {
        User newUser = new User(null, "Charlie", "charlie@example.com");
        User saved   = new User(3L,   "Charlie", "charlie@example.com");
        when(userService.save(any(User.class))).thenReturn(saved);

        mockMvc.perform(post("/api/users")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"name\":\"Charlie\",\"email\":\"charlie@example.com\"}"))
               .andExpect(status().isCreated())
               .andExpect(jsonPath("$.id").value(3))
               .andExpect(jsonPath("$.name").value("Charlie"));
    }
}
package com.example.controller;

import com.example.model.User;
import com.example.service.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping
    public List<User> getAllUsers() {
        return userService.findAll();
    }

    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        return userService.findById(id)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }

    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User saved = userService.save(user);
        return ResponseEntity.status(201).body(saved);
    }
}

Testing Services with Mockito

Service Unit Test with Mockito
package com.example.service;

import com.example.model.User;
import com.example.repository.UserRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.*;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.Optional;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;

// Pure Mockito test — no Spring context loaded (very fast)
@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    @Mock
    private UserRepository userRepository; // Mockito mock

    @InjectMocks
    private UserService userService; // Injects the mock into UserService

    @Test
    void findById_whenUserExists_shouldReturnUser() {
        User user = new User(1L, "Alice", "alice@example.com");
        when(userRepository.findById(1L)).thenReturn(Optional.of(user));

        Optional<User> result = userService.findById(1L);

        assertThat(result).isPresent();
        assertThat(result.get().getName()).isEqualTo("Alice");
        verify(userRepository).findById(1L);
    }

    @Test
    void save_withDuplicateEmail_shouldThrowException() {
        User user = new User(null, "Bob", "bob@example.com");
        when(userRepository.existsByEmail("bob@example.com")).thenReturn(true);

        assertThatThrownBy(() -> userService.save(user))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("Email already exists");

        verify(userRepository, never()).save(any());
    }
}

@DataJpaTest for Repository Testing

Repository Test with @DataJpaTest
package com.example.repository;

import com.example.model.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;

import java.util.Optional;

import static org.assertj.core.api.Assertions.*;

// @DataJpaTest: loads JPA layer only, uses H2 in-memory DB by default
// Each test runs in a transaction that is rolled back after the test
@DataJpaTest
class UserRepositoryTest {

    @Autowired
    private TestEntityManager entityManager; // Helper for persisting test data

    @Autowired
    private UserRepository userRepository;

    @Test
    void findByEmail_whenExists_shouldReturnUser() {
        // Arrange: persist a user directly via EntityManager
        User user = new User(null, "Alice", "alice@example.com");
        entityManager.persistAndFlush(user);

        // Act
        Optional<User> found = userRepository.findByEmail("alice@example.com");

        // Assert
        assertThat(found).isPresent();
        assertThat(found.get().getName()).isEqualTo("Alice");
    }

    @Test
    void existsByEmail_whenNotExists_shouldReturnFalse() {
        boolean exists = userRepository.existsByEmail("nobody@example.com");
        assertThat(exists).isFalse();
    }

    @Test
    void save_shouldPersistAndGenerateId() {
        User user = new User(null, "Bob", "bob@example.com");
        User saved = userRepository.save(user);

        assertThat(saved.getId()).isNotNull();
        assertThat(saved.getId()).isGreaterThan(0);
    }
}
Integration Test with @SpringBootTest
package com.example;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.*;

import static org.assertj.core.api.Assertions.*;

// @SpringBootTest: loads full context, starts embedded server on random port
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserIntegrationTest {

    @LocalServerPort
    private int port; // Injected random port

    @Autowired
    private TestRestTemplate restTemplate; // HTTP client for integration tests

    @Test
    void getUsers_shouldReturnOk() {
        ResponseEntity<String> response = restTemplate.getForEntity(
                "http://localhost:" + port + "/api/users", String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    @Test
    void createUser_shouldReturn201() {
        String body = "{\"name\":\"Test\",\"email\":\"test@example.com\"}";
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        ResponseEntity<String> response = restTemplate.postForEntity(
                "http://localhost:" + port + "/api/users",
                new HttpEntity<>(body, headers), String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
    }
}

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.