Test yozishga ilk qadam

01.07.2026 | Muallif: Jaxongir a.k.a | Kategoriya: Spring Boot | 20 daqiqa o'qish

Bu bo‘limda Spring Boot’da birinchi testlarni yozishni o‘rganamiz. Bbu mavzu ichida @SpringBootTest, @WebMvcTest, MockMvc, controller testlari va @MockBean bor.


1. Test nima uchun kerak?

Test - kod to‘g‘ri ishlayotganini avtomatik tekshiradigan kod.

Masalan, biz GET /users/1 endpoint yozdik. Qo‘lda Postman’da tekshirish mumkin. Lekin har safar qo‘lda tekshirish sekin va ishonchsiz.

Test bilan esa:

Kod o‘zgarsa ham endpoint buzilmaganini tekshiramiz
Buglarni erta topamiz
Refactor qilish xavfsizroq bo‘ladi
CI/CD’da avtomatik tekshiruv ishlaydi

Oddiy qilib:

Test - "men yozgan kod hali ham to‘g‘ri ishlayaptimi?" degan savolga avtomatik javob beradi.


2. Spring Boot’da testlar qayerda yoziladi?

Spring Boot loyihada testlar odatda shu joyda bo‘ladi:

src/test/java

Masalan:

src
 ├── main
 │   └── java
 │       └── uz/jts/demo
 │           ├── controller
 │           ├── service
 │           └── repository
 └── test
     └── java
         └── uz/jts/demo
             ├── controller
             ├── service
             └── repository

3. Kerakli dependency

Agar Spring Initializr’da loyiha ochsak, odatda test dependency avtomatik qo‘shiladi:

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

Bu dependency ichida quyidagilar bor:

JUnit 5
AssertJ
Mockito
Spring Test
MockMvc
JSON test utilities

4. Test turlari

Spring Boot’da boshlang'ich bosqichda 3 ta asosiy testni bilish yetarli:

Test turi

Nima tekshiradi?

Tezligi

Unit test

Bitta class yoki method

Juda tez

Slice test

Faqat ma’lum layer, masalan controller

Tez

Integration test

Butun Spring context

Sekinroq

boshlang'ich bosqichda asosiy mavzular:

@SpringBootTest
@WebMvcTest
MockMvc
@MockBean

5. Unit test nima?

Unit test - bitta classni alohida tekshirish.

Masalan, UserService bor:

@Service
public class UserService {

    public String getUserName(Long id) {
        return "Ali";
    }
}

Test:

import org.junit.jupiter.api.Test;

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

class UserServiceTest {

    @Test
    void shouldReturnUserName() {
        UserService userService = new UserService();

        String result = userService.getUserName(1L);

        assertThat(result).isEqualTo("Ali");
    }
}

Bu yerda Spring umuman ishga tushmaydi. Shuning uchun test tez ishlaydi.


6. @SpringBootTest nima?

@SpringBootTest - butun Spring Boot application context’ni ishga tushirib test qiladi.

@SpringBootTest
class DemoApplicationTests {

    @Test
    void contextLoads() {
    }
}

Bu test nimani tekshiradi?

Spring application context xatosiz ochiladimi?

Agar beanlarda muammo bo‘lsa, dependency topilmasa, config xato bo‘lsa - bu test yiqiladi.


7. contextLoads() testining ma’nosi

Spring Initializr ko‘pincha shunday test yaratadi:

@SpringBootTest
class DemoApplicationTests {

    @Test
    void contextLoads() {
    }
}

Ichida hech narsa yo‘qdek ko‘rinadi. Lekin aslida muhim:

Spring Boot ishga tushadi
Beanlar yaratiladi
Dependency injection tekshiriladi
Configuration tekshiriladi

Agar app start bo‘lmasa, test fail bo‘ladi.


8. @SpringBootTest qachon ishlatiladi?

@SpringBootTest quyidagi holatda ishlatiladi:

Butun application start bo‘lishini tekshirish
Bir nechta layer birga ishlashini tekshirish
Real database yoki test database bilan integration test
Configuration to‘g‘ri ekanini tekshirish

Lekin har bir kichik testga @SpringBootTest ishlatish shart emas.

Sababi:

Sekinroq ishlaydi
Butun context ochiladi
Testlar ko‘payganda vaqt cho‘ziladi

9. @WebMvcTest nima?

@WebMvcTest - faqat web/controller layer’ni test qilish uchun ishlatiladi.

Masalan:

@WebMvcTest(UserController.class)
class UserControllerTest {
}

Bu testda Spring faqat MVC qismni ko‘taradi:

Controller
JSON converter
Validation
Spring MVC infrastructure

Lekin service, repository, database to‘liq ochilmaydi.

Shuning uchun controller dependency’larini mock qilish kerak bo‘ladi.


10. Mock nima?

Mock - haqiqiy obyekt o‘rniga ishlatiladigan soxta obyekt.

Masalan, UserController UserServicega bog‘liq:

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

    private final UserService userService;

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

Controller testida haqiqiy UserServiceni ishlatmasdan mock qilamiz.

Ya’ni:

"Agar userService.getUser(1L) chaqirilsa, Ali qaytar" deb oldindan aytib qo‘yamiz.


11. @MockBean nima?

@MockBean - Spring context ichiga mock bean qo‘shadi.

@MockBean
private UserService userService;

Bu degani:

Haqiqiy UserService o‘rniga mock UserService ishlatiladi
Controller shu mock service’ni oladi
Testda service javobini o‘zimiz belgilaymiz

Muhim: Spring Boot 3.4+ da @MockBean deprecated bo‘lgan. Yangi loyihalarda @MockitoBean ishlatiladi. Lekin ko‘p real loyihalarda hali ham @MockBean uchraydi.


12. MockMvc nima?

MockMvc - controller endpointlarni haqiqiy server ochmasdan test qilish vositasi.

Masalan, test ichida:

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

Bu haqiqiy browser yoki Postman emas. Lekin Spring MVC request/response jarayonini test qiladi.


13. Mini loyiha: User API

Avval oddiy API tayyorlaymiz.

DTO

public record UserResponse(
        Long id,
        String name,
        String email
) {
}

Service

@Service
public class UserService {

    public UserResponse getUserById(Long id) {
        return new UserResponse(id, "Ali", "ali@mail.com");
    }

    public List<UserResponse> getUsers() {
        return List.of(
                new UserResponse(1L, "Ali", "ali@mail.com"),
                new UserResponse(2L, "Vali", "vali@mail.com")
        );
    }
}

Controller

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

    private final UserService userService;

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

    @GetMapping("/{id}")
    public UserResponse getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }

    @GetMapping
    public List<UserResponse> getUsers() {
        return userService.getUsers();
    }
}

14. Birinchi @WebMvcTest

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.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;

import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(UserController.class)
class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockitoBean
    private UserService userService;

    @Test
    void shouldReturnUserById() throws Exception {
        when(userService.getUserById(1L))
                .thenReturn(new UserResponse(1L, "Ali", "ali@mail.com"));

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

Bu test:

GET /users/1 endpointni chaqiradi
HTTP status 200 OK ekanini tekshiradi
UserService haqiqiy emas, mock

15. JSON response tekshirish

Faqat status emas, body ichidagi qiymatlarni ham tekshiramiz.

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.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;

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

@WebMvcTest(UserController.class)
class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockitoBean
    private UserService userService;

    @Test
    void shouldReturnUserById() throws Exception {
        when(userService.getUserById(1L))
                .thenReturn(new UserResponse(1L, "Ali", "ali@mail.com"));

        mockMvc.perform(get("/users/1"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").value(1))
                .andExpect(jsonPath("$.name").value("Ali"))
                .andExpect(jsonPath("$.email").value("ali@mail.com"));
    }
}

Bu yerda:

$.id     → JSON ichidagi id field
$.name   → JSON ichidagi name field
$.email  → JSON ichidagi email field

16. List response test qilish

Endpoint:

GET /users

Test:

@Test
void shouldReturnUsers() throws Exception {
    when(userService.getUsers())
            .thenReturn(List.of(
                    new UserResponse(1L, "Ali", "ali@mail.com"),
                    new UserResponse(2L, "Vali", "vali@mail.com")
            ));

    mockMvc.perform(get("/users"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.length()").value(2))
            .andExpect(jsonPath("$[0].name").value("Ali"))
            .andExpect(jsonPath("$[1].name").value("Vali"));
}

JSON array bo‘lsa:

$[0] → birinchi element
$[1] → ikkinchi element

17. POST endpoint test qilish

Endi create endpoint qo‘shamiz.

Request DTO

public record CreateUserRequest(
        String name,
        String email
) {
}

Service

public UserResponse createUser(CreateUserRequest request) {
    return new UserResponse(1L, request.name(), request.email());
}

Controller

@PostMapping
public ResponseEntity<UserResponse> createUser(
        @RequestBody CreateUserRequest request
) {
    UserResponse response = userService.createUser(request);

    return ResponseEntity
            .status(HttpStatus.CREATED)
            .body(response);
}

18. POST test

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.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;

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

@WebMvcTest(UserController.class)
class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockitoBean
    private UserService userService;

    @Test
    void shouldCreateUser() throws Exception {
        when(userService.createUser(any(CreateUserRequest.class)))
                .thenReturn(new UserResponse(1L, "Ali", "ali@mail.com"));

        String requestJson = """
                {
                  "name": "Ali",
                  "email": "ali@mail.com"
                }
                """;

        mockMvc.perform(post("/users")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(requestJson))
                .andExpect(status().isCreated())
                .andExpect(jsonPath("$.id").value(1))
                .andExpect(jsonPath("$.name").value("Ali"))
                .andExpect(jsonPath("$.email").value("ali@mail.com"));
    }
}

Muhim qismlar:

.contentType(MediaType.APPLICATION_JSON) → JSON yuboryapmiz
.content(requestJson) → request body
status().isCreated() → 201 Created kutyapmiz

19. any() nima?

when(userService.createUser(any(CreateUserRequest.class)))

Bu Mockito’dan keladi.

Ma’nosi:

createUser() ichiga istalgan CreateUserRequest kelsa, mana bu response qaytar.

Agar aniq object solishtirmoqchi bo‘lsang, keyin ArgumentCaptor o‘rganiladi. boshlang'ich bosqichda any() yetarli.


20. @SpringBootTest + MockMvc

Ba’zan butun application context bilan endpoint test qilamiz.

@SpringBootTest
@AutoConfigureMockMvc
class UserApiIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void shouldReturnUsers() throws Exception {
        mockMvc.perform(get("/users"))
                .andExpect(status().isOk());
    }
}

Bu @WebMvcTestdan farqli:

Annotation

Nima ochiladi?

@WebMvcTest

Faqat controller/web layer

@SpringBootTest

Butun Spring Boot context


21. @WebMvcTest vs @SpringBootTest

Mezon

@WebMvcTest

@SpringBootTest

Maqsad

Controller test

Integration test

Tezlik

Tez

Sekinroq

Service

Mock qilinadi

Haqiqiy bean

Repository

Odatda yo‘q

Haqiqiy yoki test DB

Qachon?

Endpoint response/status tekshirish

Layerlar birga ishlashini tekshirish

Asosiy qoida:

Controller alohida test → @WebMvcTest
Butun app integration test → @SpringBootTest

22. Service unit test

Service test uchun ko‘pincha Spring shart emas.

Masalan:

class UserServiceTest {

    @Test
    void shouldReturnUserById() {
        UserService userService = new UserService();

        UserResponse response = userService.getUserById(1L);

        assertThat(response.id()).isEqualTo(1L);
        assertThat(response.name()).isEqualTo("Ali");
    }
}

Agar service repository’ga bog‘liq bo‘lsa, repository mock qilinadi.


23. Service + mock repository

Repository

public interface UserRepository extends JpaRepository<User, Long> {
}

Service

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public UserResponse getUserById(Long id) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("User topilmadi"));

        return new UserResponse(user.getId(), user.getName(), user.getEmail());
    }
}

Test

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void shouldReturnUserById() {
        User user = new User("Ali", "ali@mail.com");
        user.setId(1L);

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

        UserResponse response = userService.getUserById(1L);

        assertThat(response.id()).isEqualTo(1L);
        assertThat(response.name()).isEqualTo("Ali");
        assertThat(response.email()).isEqualTo("ali@mail.com");
    }
}

Bu yerda Spring yo‘q. Mockito bor.


24. @Mock vs @MockitoBean

Annotation

Qayerda ishlatiladi?

@Mock

Oddiy unit testda, Spring context yo‘q

@InjectMocks

Mocklarni class constructoriga beradi

@MockitoBean

Spring test context ichida mock bean yaratadi

@MockBean

Eskiroq Spring Boot loyihalarda ishlatiladi

Spring Boot 3.4+:

@MockitoBean
private UserService userService;

Eski loyihalarda ko‘proq ko‘rasan:

@MockBean
private UserService userService;

25. Test naming

Test nomi tushunarli bo‘lishi kerak.

Yomon:

@Test
void test1() {
}

Yaxshi:

@Test
void shouldReturnUserById() {
}

Yana yaxshi:

@Test
void shouldReturn404WhenUserNotFound() {
}

26. Test structure: Arrange, Act, Assert

Yaxshi test odatda 3 qismdan iborat:

Arrange → test uchun data tayyorlash
Act     → method yoki endpoint chaqirish
Assert  → natijani tekshirish

Misol:

@Test
void shouldReturnUserById() {
    // Arrange
    UserService userService = new UserService();

    // Act
    UserResponse response = userService.getUserById(1L);

    // Assert
    assertThat(response.name()).isEqualTo("Ali");
}

27. Error case test qilish

Faqat muvaffaqiyatli holatni emas, xato holatni ham test qilish kerak.

Masalan service user topilmasa exception tashlaydi:

public UserResponse getUserById(Long id) {
    User user = userRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("User topilmadi"));

    return new UserResponse(user.getId(), user.getName(), user.getEmail());
}

Test:

import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.when;

@Test
void shouldThrowExceptionWhenUserNotFound() {
    when(userRepository.findById(99L))
            .thenReturn(Optional.empty());

    assertThatThrownBy(() -> userService.getUserById(99L))
            .isInstanceOf(RuntimeException.class)
            .hasMessage("User topilmadi");
}

28. Controller 404 test

Real loyihada exception handler bo‘lsa, 404 qaytarish mumkin.

Masalan:

@ResponseStatus(HttpStatus.NOT_FOUND)
public class UserNotFoundException extends RuntimeException {

    public UserNotFoundException(String message) {
        super(message);
    }
}

Service:

public UserResponse getUserById(Long id) {
    User user = userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException("User topilmadi"));

    return new UserResponse(user.getId(), user.getName(), user.getEmail());
}

Test:

@Test
void shouldReturn404WhenUserNotFound() throws Exception {
    when(userService.getUserById(99L))
            .thenThrow(new UserNotFoundException("User topilmadi"));

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

29. Eng ko‘p uchraydigan xatolar

1. @WebMvcTestda service mock qilinmagan

Xato:

No qualifying bean of type 'UserService' available

Sabab:

@WebMvcTest faqat controller layerni ochadi
UserService bean sifatida topilmaydi
Uni @MockitoBean yoki @MockBean qilish kerak

To‘g‘ri:

@MockitoBean
private UserService userService;

2. POST testda contentType yo‘q

Xato:

mockMvc.perform(post("/users")
        .content(requestJson))

To‘g‘ri:

mockMvc.perform(post("/users")
        .contentType(MediaType.APPLICATION_JSON)
        .content(requestJson))

3. JSON path noto‘g‘ri

Agar response object bo‘lsa:

{
  "id": 1,
  "name": "Ali"
}

To‘g‘ri:

jsonPath("$.name").value("Ali")

Agar response array bo‘lsa:

[
  {
    "id": 1,
    "name": "Ali"
  }
]

To‘g‘ri:

jsonPath("$[0].name").value("Ali")

4. Testga butun Spring contextni keraksiz ochish

Yomon:

@SpringBootTest
class UserServiceTest {
}

Agar faqat service logic test qilinayotgan bo‘lsa, oddiy Mockito unit test yetarli.


30. Interview uchun javoblar

Savol: @SpringBootTest nima?

@SpringBootTest butun Spring Boot application context’ni ishga tushirib test qiladi. Integration testlar uchun ishlatiladi.

Savol: @WebMvcTest nima?

@WebMvcTest faqat Spring MVC/controller layer’ni test qilish uchun ishlatiladi. Service va repository odatda mock qilinadi.

Savol: MockMvc nima?

MockMvc haqiqiy server ochmasdan Spring MVC endpointlarini test qilish imkonini beradi.

Savol: @MockBean yoki @MockitoBean nima?

Spring test context ichida haqiqiy bean o‘rniga mock bean qo‘yish uchun ishlatiladi. Spring Boot 3.4+ da @MockitoBean tavsiya qilinadi, eski loyihalarda @MockBean ko‘p uchraydi.

Savol: Unit test va integration test farqi?

Unit test bitta class yoki methodni alohida tekshiradi. Integration test esa bir nechta layer yoki butun application context birga ishlashini tekshiradi.


31. Boshlang'ich uchun xulosa

Bugungi mavzudan eslab qoling:

Test - kod to‘g‘ri ishlashini avtomatik tekshiradi
@SpringBootTest - butun Spring contextni ochadi
@WebMvcTest - faqat controller/web layerni test qiladi
MockMvc - endpointlarni server ochmasdan test qiladi
@MockitoBean / @MockBean - Spring context ichida mock bean beradi
@Mock - oddiy Mockito mock
@InjectMocks - mocklarni classga inject qiladi
status().isOk() - 200 OK tekshiradi
jsonPath("$.name") - JSON field tekshiradi

32. Amaliy vazifa

ProductController uchun test yoz:

Endpointlar

GET  /products/1
GET  /products
POST /products

Response DTO

public record ProductResponse(
        Long id,
        String name,
        Double price
) {
}

Request DTO

public record CreateProductRequest(
        String name,
        Double price
) {
}

Testlar

shouldReturnProductById()
shouldReturnProducts()
shouldCreateProduct()
shouldReturn404WhenProductNotFound()