Testing - Production-grade

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

Bu bo‘limda Testcontainers, @DataJpaTest, @WebMvcTest, test slices, WireMock, @TestConfiguration, test beans, Spring Cloud Contract, va full context vs sliced tests trade-offlarni ko‘ramiz.

Spring Boot testlarda JUnit, Spring Test, AssertJ, Hamcrest, Mockito, JSONassert, JsonPath va boshqa kutubxonalar uchun qulay starter beradi; spring-boot-starter-test odatda asosiy test dependency sifatida ishlatiladi. (Home)


1. Production-grade testing nima?

Oddiy test:

Method ishlayaptimi?

Production-grade test esa:

Real DB bilan ishlaydimi?
Transaction to‘g‘rimi?
REST endpoint validatsiyasi to‘g‘rimi?
Security ishlayaptimi?
External API xato bersa nima bo‘ladi?
Migrationlar real DBda yuradimi?
Kafka/RabbitMQ event to‘g‘ri ketadimi?

Ya’ni maqsad faqat code coverage emas.

Maqsad:

Productionga chiqadigan xatolarni oldindan ushlash.


2. Test turlari

Test turi

Nima tekshiradi?

Tezligi

Unit test

Bitta class/method

Juda tez

Slice test

Springning bir qismi

Tez

Integration test

Bir nechta layer + real dependency

O‘rtacha

End-to-end test

Butun system flow

Sekin

Contract test

Service’lar orasidagi API kelishuvi

O‘rtacha

Production-grade testingda bularning hammasi kerak. Lekin hamma narsani @SpringBootTest bilan test qilish yomon.


3. Test pyramid

Yaxshi test strategiya:

        E2E tests
      Integration tests
    Slice / Contract tests
  Unit tests

Pastda ko‘p test, yuqorida kam test bo‘ladi.

Layer

Tavsiya

Unit

Ko‘p bo‘lsin

Slice

Yetarli bo‘lsin

Integration

Muhim flowlar

E2E

Juda muhim user journeylar

Contract

Microservice/API integratsiyalar


4. spring-boot-starter-test

Maven:

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

Odatda ichida quyidagilar bo‘ladi:

JUnit Jupiter
Spring Test
AssertJ
Mockito
Hamcrest
JSONassert
JsonPath

Unit test misol:

class PriceCalculatorTest {

    private final PriceCalculator calculator = new PriceCalculator();

    @Test
    void shouldApplyDiscount() {
        BigDecimal result = calculator.applyDiscount(
                BigDecimal.valueOf(100),
                BigDecimal.valueOf(10)
        );

        assertThat(result).isEqualByComparingTo("90");
    }
}

Bu Spring context ochmaydi. Juda tez.


5. @SpringBootTest

@SpringBootTest butun Spring application contextni ko‘taradi.

@SpringBootTest
class OrderServiceIntegrationTest {

    @Autowired
    private OrderService orderService;

    @Test
    void shouldCreateOrder() {
        Long orderId = orderService.createOrder(new CreateOrderRequest(1L));

        assertThat(orderId).isNotNull();
    }
}

Bu foydali, lekin og‘ir.

@SpringBootTest ishlating:

  • full application wiring tekshirish kerak bo‘lsa;

  • security + web + DB birga tekshirilsa;

  • real integration flow kerak bo‘lsa;

  • configuration xatolarini ushlash kerak bo‘lsa.

Har bitta service method uchun @SpringBootTest ishlatish noto‘g‘ri.


6. Test slice nima?

Test slice - Spring contextning faqat kerakli qismini ko‘tarish.

Masalan:

Annotation

Nima test qiladi?

@WebMvcTest

Controller layer

@DataJpaTest

JPA/repository layer

@JsonTest

JSON serialization/deserialization

@RestClientTest

REST client

@JdbcTest

JDBC layer

Afzallik:

Full context emas
Tezroq
Aniqroq
Kamroq dependency

7. @DataJpaTest

@DataJpaTest JPA repositorylarni test qilish uchun.

@DataJpaTest
class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    void shouldFindByUsername() {
        User user = new User();
        user.setUsername("ali");
        userRepository.save(user);

        Optional<User> result = userRepository.findByUsername("ali");

        assertThat(result).isPresent();
    }
}

@DataJpaTest odatda:

  • repository beanlarni ko‘taradi;

  • JPA configni yuklaydi;

  • transaction bilan test qiladi;

  • testdan keyin rollback qiladi.


8. @DataJpaTest muammosi: H2 aldamchi bo‘lishi mumkin

Ko‘p projectlarda @DataJpaTest H2 bilan ishlaydi.

Lekin production PostgreSQL/MySQL bo‘lsa, H2 ba’zan boshqacha ishlaydi:

SQL syntax farq qiladi
JSONB yo‘q
Array type boshqacha
Index behavior farq qiladi
Migrationlar boshqacha yuradi
Locking boshqacha

Shuning uchun production-grade testda real DBga yaqin test kerak.

Yechim: Testcontainers.


9. Testcontainers nima?

Testcontainers - test vaqtida Docker containerda real dependency ko‘tarish imkonini beradi.

Masalan:

PostgreSQL container
Redis container
Kafka container
RabbitMQ container
MongoDB container

Test tugagach container tozalanadi.

Spring Boot Testcontainers integration, jumladan @ServiceConnection, test dependencylarni connection details sifatida avtomatik ulashni qo‘llab-quvvatlaydi. (Home)


10. PostgreSQL bilan Testcontainers

Dependency:

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

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>postgresql</artifactId>
    <scope>test</scope>
</dependency>

Test:

@DataJpaTest
@Testcontainers
class UserRepositoryPostgresTest {

    @Container
    @ServiceConnection
    static PostgreSQLContainer<?> postgres =
            new PostgreSQLContainer<>("postgres:16");

    @Autowired
    private UserRepository userRepository;

    @Test
    void shouldSaveUserInRealPostgres() {
        User user = new User();
        user.setUsername("ali");

        User saved = userRepository.save(user);

        assertThat(saved.getId()).isNotNull();
    }
}

@ServiceConnection Spring Bootga container connectionni avtomatik ulashga yordam beradi.


11. Testcontainers bilan migrationlarni test qilish

Agar Flyway yoki Liquibase ishlatsangiz, real PostgreSQL containerda migrationlar ham yuradi.

Bu juda foydali:

V1__init.sql production DBda yuradimi?
Column type to‘g‘rimi?
Index syntax to‘g‘rimi?
Constraintlar ishlaydimi?

Misol:

@SpringBootTest
@Testcontainers
class MigrationIntegrationTest {

    @Container
    @ServiceConnection
    static PostgreSQLContainer<?> postgres =
            new PostgreSQLContainer<>("postgres:16");

    @Test
    void contextLoadsWithMigrations() {
        // Context ko‘tarilsa, migrationlar muvaffaqiyatli yurdi
    }
}

12. Testcontainers qachon ishlatiladi?

Yaxshi joylar:

Dependency

Nega real container kerak?

PostgreSQL

SQL dialect, migration, locking

Redis

TTL, serialization, cache behavior

Kafka

consumer/producer integration

RabbitMQ

routing, DLQ, retry

Elasticsearch

query/index behavior

MinIO/S3

file storage integration

Lekin hamma unit testga container qo‘shish yomon. Container testlar sekinroq bo‘ladi.


13. @WebMvcTest

Controller layer test.

@WebMvcTest(UserController.class)
class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockitoBean
    private UserService userService;

    @Test
    void shouldReturnUser() throws Exception {
        given(userService.getById(1L))
                .willReturn(new UserDto(1L, "Ali"));

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

@WebMvcTest nimani tekshiradi?

@RequestMapping
@PathVariable
@RequestParam
@RequestBody
Validation
ControllerAdvice
JSON response
HTTP status

Service va DBni test qilmaydi. Service mock qilinadi.


14. Controller validation test

DTO:

public record CreateUserRequest(
        @NotBlank String name,
        @Email String email
) {
}

Controller:

@PostMapping("/api/users")
public ResponseEntity<UserDto> create(
        @Valid @RequestBody CreateUserRequest request
) {
    return ResponseEntity.status(HttpStatus.CREATED)
            .body(userService.create(request));
}

Test:

@Test
void shouldReturnBadRequestWhenEmailInvalid() throws Exception {
    String body = """
            {
              "name": "Ali",
              "email": "wrong-email"
            }
            """;

    mockMvc.perform(post("/api/users")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(body))
            .andExpect(status().isBadRequest());
}

Bu productionda juda kerak. Chunki validation xatolari controller layerda ushlanadi.


15. @WebMvcTest va Security

Agar Spring Security bo‘lsa, @WebMvcTestda security ham ta’sir qilishi mumkin.

Authenticated user bilan test:

@Test
@WithMockUser(username = "admin", roles = "ADMIN")
void shouldAccessAdminEndpoint() throws Exception {
    mockMvc.perform(get("/api/admin/users"))
            .andExpect(status().isOk());
}

Ruxsat yo‘q holat:

@Test
@WithMockUser(username = "user", roles = "USER")
void shouldReturnForbiddenForUser() throws Exception {
    mockMvc.perform(get("/api/admin/users"))
            .andExpect(status().isForbidden());
}

Bu endpoint authorization qoidalarini test qiladi.


16. Service unit test

Service logicni Spring contextsiz test qilish kerak.

class OrderServiceTest {

    private OrderRepository orderRepository;
    private PaymentService paymentService;
    private OrderService orderService;

    @BeforeEach
    void setUp() {
        orderRepository = mock(OrderRepository.class);
        paymentService = mock(PaymentService.class);
        orderService = new OrderService(orderRepository, paymentService);
    }

    @Test
    void shouldCreateOrder() {
        Order saved = new Order();
        saved.setId(1L);

        when(orderRepository.save(any(Order.class))).thenReturn(saved);

        Long orderId = orderService.createOrder(new CreateOrderRequest(10L));

        assertThat(orderId).isEqualTo(1L);
        verify(orderRepository).save(any(Order.class));
    }
}

Afzallik:

Tez
Aniq
Spring context kerak emas
Business logicga fokus

17. Mockito bilan xatolar

Yomon test:

@Test
void badTest() {
    when(repository.save(any())).thenReturn(new Order());

    service.createOrder(request);

    verify(repository).save(any());
}

Bu faqat method chaqirilganini tekshiradi. Business natijani tekshirmaydi.

Yaxshiroq:

@Test
void shouldSetInitialStatusCreated() {
    ArgumentCaptor<Order> captor = ArgumentCaptor.forClass(Order.class);

    when(repository.save(any())).thenAnswer(invocation -> invocation.getArgument(0));

    service.createOrder(request);

    verify(repository).save(captor.capture());

    Order order = captor.getValue();

    assertThat(order.getStatus()).isEqualTo(OrderStatus.CREATED);
}

Bu real business rule tekshiradi.


18. @TestConfiguration

Ba’zan test uchun alohida bean kerak.

@TestConfiguration
public class TestClockConfig {

    @Bean
    public Clock fixedClock() {
        return Clock.fixed(
                Instant.parse("2026-01-01T00:00:00Z"),
                ZoneOffset.UTC
        );
    }
}

Test:

@SpringBootTest
@Import(TestClockConfig.class)
class OrderServiceTest {

    @Autowired
    private OrderService orderService;

    @Test
    void shouldUseFixedTime() {
        OrderDto order = orderService.createOrder(request);

        assertThat(order.createdAt())
                .isEqualTo(Instant.parse("2026-01-01T00:00:00Z"));
    }
}

Bu vaqtga bog‘liq testlarni deterministic qiladi.


19. Test beans va @MockitoBean

Spring context ichida real beanni mock qilish kerak bo‘lsa:

@SpringBootTest
class OrderIntegrationTest {

    @MockitoBean
    private PaymentClient paymentClient;

    @Autowired
    private OrderService orderService;

    @Test
    void shouldCreateOrderWhenPaymentSuccess() {
        given(paymentClient.charge(any()))
                .willReturn(new PaymentResult("SUCCESS"));

        OrderDto result = orderService.createOrder(request);

        assertThat(result.status()).isEqualTo(OrderStatus.PAID);
    }
}

Bu yerda PaymentClient external dependency. Real API chaqirilmaydi.


20. WireMock nima?

WireMock - external HTTP APIlarni mock qilish uchun ishlatiladi.

Masalan service Stripe/Click/Payme yoki boshqa REST API chaqirsa, testda real APIga chiqish yomon.

WireMock bilan test ichida fake HTTP server ko‘tariladi:

App -> WireMock server -> fake response

WireMock Spring Boot integration JUnit testlarda bir yoki bir nechta WireMock instanceni declarative tarzda sozlash va ishga tushirish imkonini beradi. (WireMock)


21. WireMock bilan external API test

Dependency misol:

<dependency>
    <groupId>org.wiremock.integrations</groupId>
    <artifactId>wiremock-spring-boot</artifactId>
    <scope>test</scope>
</dependency>

Test:

@SpringBootTest
@EnableWireMock({
        @ConfigureWireMock(
                name = "payment-service",
                property = "payment.base-url"
        )
})
class PaymentClientTest {

    @Autowired
    private PaymentClient paymentClient;

    @Test
    void shouldChargeSuccessfully() {
        stubFor(post("/charge")
                .willReturn(okJson("""
                        {
                          "status": "SUCCESS",
                          "transactionId": "tx-123"
                        }
                        """)));

        PaymentResult result = paymentClient.charge(
                new PaymentRequest(100_000)
        );

        assertThat(result.status()).isEqualTo("SUCCESS");
    }
}

Bu test:

Real external API chaqirmaydi
HTTP client serialization/deserializationni tekshiradi
Timeout/error case yozish mumkin

22. WireMock bilan error case

@Test
void shouldHandlePaymentTimeout() {
    stubFor(post("/charge")
            .willReturn(aResponse()
                    .withFixedDelay(5000)
                    .withStatus(200)));

    assertThatThrownBy(() ->
            paymentClient.charge(new PaymentRequest(100_000))
    ).isInstanceOf(PaymentTimeoutException.class);
}

Bu productionda muhim:

External API sekin bo‘lsa nima qilamiz?
Retry bormi?
Timeout bormi?
Fallback bormi?

23. REST client testda nimalar tekshiriladi?

Holat

Tekshirish kerak

200 OK

Response parse bo‘ladimi

400 Bad Request

Business exceptionga aylanadimi

401/403

Auth error handle qilinadimi

500

Retry/fallback bormi

Timeout

Timeout exception to‘g‘rimi

Invalid JSON

Parse error handle qilinadimi

External API testlari production-grade testingda majburiyga yaqin.


24. Contract testing nima?

Microservice’larda muammo:

Order service Payment service APIga ishonadi.
Payment service response formatni o‘zgartirib yubordi.
Order service productionda yiqildi.

Contract testing shu muammoni oldini oladi.

Contract - consumer va provider orasidagi kelishuv:

Request shunday bo‘ladi
Response shunday bo‘ladi
Status code shunday bo‘ladi
Fieldlar shunday bo‘ladi

Spring Cloud Contract consumer-driven va producer-driven contract testingni qo‘llab-quvvatlaydi. (Home)


25. Spring Cloud Contract nima qiladi?

Spring Cloud Contract odatda:

1. Contract yoziladi
2. Provider uchun test generate qiladi
3. Consumer uchun stub generate qiladi
4. API contract buzilsa build fail bo‘ladi

Contract misol:

Contract.make {
    request {
        method 'GET'
        url '/payments/123'
    }
    response {
        status OK()
        body(
            paymentId: 123,
            status: 'SUCCESS'
        )
        headers {
            contentType(applicationJson())
        }
    }
}

Agar provider response’dan status fieldni olib tashlasa, contract test fail bo‘ladi.


26. Contract test qachon kerak?

Kerak:

Holat

Sabab

Microservices

APIlar mustaqil deploy bo‘ladi

External team API

Kelishuv buzilishi xavfli

Frontend/backend contract

Response format muhim

Public API

Backward compatibility muhim

Event/message schema

Consumerlar yiqilmasligi kerak

Kerak emas yoki ortiqcha:

Kichik monolith
Bitta jamoa ichidagi oddiy CRUD
Tez-tez o‘zgaradigan ichki experimental API

27. Testcontainers + WireMock + SpringBootTest kombinatsiyasi

Real integration test:

Spring Boot app
  + real PostgreSQL container
  + fake Payment API WireMock
  + full context

Misol:

@SpringBootTest
@Testcontainers
@EnableWireMock({
        @ConfigureWireMock(
                name = "payment-service",
                property = "payment.base-url"
        )
})
class OrderFlowIntegrationTest {

    @Container
    @ServiceConnection
    static PostgreSQLContainer<?> postgres =
            new PostgreSQLContainer<>("postgres:16");

    @Autowired
    private OrderService orderService;

    @Test
    void shouldCreatePaidOrder() {
        stubFor(post("/charge")
                .willReturn(okJson("""
                        {
                          "status": "SUCCESS",
                          "transactionId": "tx-1"
                        }
                        """)));

        OrderDto order = orderService.createOrder(
                new CreateOrderRequest(1L, BigDecimal.valueOf(100))
        );

        assertThat(order.status()).isEqualTo(OrderStatus.PAID);
    }
}

Bu full integration test. Bunday testlarni ko‘p yozish kerak emas, lekin critical flowlar uchun juda kuchli.


28. Test slices vs full context

Mezon

Slice test

Full context

Tezlik

Tez

Sekinroq

Scope

Bitta layer

Butun app

Debug

Osonroq

Murakkabroq

Configuration bug

Kamroq ushlaydi

Ko‘proq ushlaydi

Real flow

Cheklangan

Kuchli

Qachon

Controller/repository/client

Critical integration

Qoida:

Ko‘p slice/unit test
Kamroq full integration test
Juda kam E2E test

29. Test data strategy

Testlarda data tayyorlash ham muhim.

Yomon:

@Test
void test() {
    User user = new User();
    user.setName("Ali");
    user.setPhone("998901234567");
    user.setStatus(UserStatus.ACTIVE);
    user.setCreatedAt(LocalDateTime.now());
    user.setUpdatedAt(LocalDateTime.now());
    // har testda takror
}

Yaxshi: test factory.

public class TestUsers {

    public static User activeUser() {
        User user = new User();
        user.setName("Ali");
        user.setPhone("998901234567");
        user.setStatus(UserStatus.ACTIVE);
        return user;
    }
}

Ishlatish:

User user = TestUsers.activeUser();

Yana yaxshi: builder.

User user = UserTestBuilder.aUser()
        .withName("Ali")
        .active()
        .build();

30. Test data cleanup

Integration testlarda data bir-biriga ta’sir qilmasligi kerak.

Variantlar:

Usul

Izoh

Transaction rollback

@DataJpaTestda qulay

@Sql cleanup

Aniq SQL bilan tozalash

Testcontainers fresh DB

Eng toza, lekin sekinroq

Truncate before each test

Integration testlarda ishlaydi

Unique data

Testlar parallel ishlaganda foydali

Misol:

@Sql(scripts = "/cleanup.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)

cleanup.sql:

delete from orders;
delete from users;

Foreign key tartibiga e’tibor bering.


31. Transactional testlarda ehtiyot bo‘ling

@Transactional test method oxirida rollback qiladi.

Bu ba’zan aldamchi bo‘ladi:

@Test
@Transactional
void shouldPublishAfterCommitEvent() {
    orderService.createOrder(request);

    // AFTER_COMMIT listener ishlamasligi mumkin,
    // chunki test rollback bo‘ladi
}

Agar commit behavior test qilinayotgan bo‘lsa, test transactionni boshqacha boshqarish kerak.

Masalan:

@SpringBootTest
class OrderEventIntegrationTest {

    @Autowired
    private OrderService orderService;

    @Test
    void shouldPublishEventAfterCommit() {
        orderService.createOrder(request);

        await().atMost(Duration.ofSeconds(5))
                .untilAsserted(() ->
                        assertThat(notificationRepository.count()).isEqualTo(1)
                );
    }
}

Bu yerda service ichidagi transaction commit bo‘ladi.


32. Async testlar

Async/event/message testlarda darhol assert qilish xato bo‘lishi mumkin.

Yomon:

orderService.createOrder(request);

assertThat(emailRepository.count()).isEqualTo(1);

Email async ishlasa, hali tugamagan bo‘lishi mumkin.

Yaxshi: Awaitility.

<dependency>
    <groupId>org.awaitility</groupId>
    <artifactId>awaitility</artifactId>
    <scope>test</scope>
</dependency>
orderService.createOrder(request);

await().atMost(Duration.ofSeconds(5))
        .untilAsserted(() ->
                assertThat(emailRepository.count()).isEqualTo(1)
        );

33. Kafka/RabbitMQ integration test

Testcontainers bilan broker ko‘tarish mumkin.

Kafka testning maqsadi:

Producer topicga event yubordimi?
Consumer eventni o‘qidimi?
DLT ishlaydimi?
Serialization to‘g‘rimi?

RabbitMQ testning maqsadi:

Exchange/queue binding to‘g‘rimi?
Routing key to‘g‘rimi?
Consumer message handle qilyaptimi?
DLQga tushyaptimi?

Bu testlar og‘irroq. Faqat muhim messaging flowlar uchun yoziladi.


34. Security integration test

@SpringBootTest + MockMvc:

@SpringBootTest
@AutoConfigureMockMvc
class SecurityIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void shouldReturnUnauthorizedWithoutToken() throws Exception {
        mockMvc.perform(get("/api/orders"))
                .andExpect(status().isUnauthorized());
    }

    @Test
    @WithMockUser(roles = "ADMIN")
    void shouldAllowAdmin() throws Exception {
        mockMvc.perform(get("/api/admin/users"))
                .andExpect(status().isOk());
    }

    @Test
    @WithMockUser(roles = "USER")
    void shouldRejectUserForAdminEndpoint() throws Exception {
        mockMvc.perform(get("/api/admin/users"))
                .andExpect(status().isForbidden());
    }
}

JWT custom filter bo‘lsa, haqiqiy JWT bilan ham test qilish mumkin.


35. API response contract test

Controller testda faqat status emas, response shape ham tekshiring.

mockMvc.perform(get("/api/users/1"))
        .andExpect(status().isOk())
        .andExpect(jsonPath("$.id").value(1))
        .andExpect(jsonPath("$.name").exists())
        .andExpect(jsonPath("$.password").doesNotExist());

Muhim:

passwordHash chiqmayaptimi?
internal field chiqmayaptimi?
error response format bir xilmi?

36. Error response test

Global exception handler bo‘lsa, test qiling.

@Test
void shouldReturnNotFoundResponse() throws Exception {
    given(userService.getById(99L))
            .willThrow(new UserNotFoundException(99L));

    mockMvc.perform(get("/api/users/99"))
            .andExpect(status().isNotFound())
            .andExpect(jsonPath("$.code").value("USER_NOT_FOUND"))
            .andExpect(jsonPath("$.message").exists());
}

Bu frontend/mobile uchun juda muhim.


37. Performance-sensitive query test

Repository querylar uchun ba’zan query count test qilish kerak.

Masalan N+1 oldini olish:

findOrdersWithUser() 1 query ishlatishi kerak

Buni Hibernate statistics yoki datasource-proxy bilan tekshirish mumkin.

Maqsad:

N+1 muammo productionga chiqmasin

Ayniqsa:

order.getUser()
order.getItems()
user.getRoles()

kabi relationlarda.


38. Test profile

application-test.yml:

spring:
  jpa:
    hibernate:
      ddl-auto: validate
  flyway:
    enabled: true

logging:
  level:
    org.springframework.test: INFO

Testda profile:

@ActiveProfiles("test")
@SpringBootTest
class OrderServiceTest {
}

Muhim:

test config productionga yaqin bo‘lsin
lekin external dependencylar test/fake bo‘lsin

39. Flaky test nima?

Flaky test - ba’zan o‘tadi, ba’zan yiqiladi.

Sabablar:

Sabab

Misol

Time dependency

LocalDateTime.now()

Async race

event hali tugamagan

Shared state

testlar bir DB datadan foydalanadi

Random data

predictable emas

External API

real internetga chiqadi

Test order dependency

bir test boshqasiga bog‘liq

Parallel execution

shared resource conflict

Flaky test ishonchni buzadi. Jamoa test fail bo‘lsa ham e’tibor bermay qo‘yadi.


40. Flaky testni kamaytirish

Muammo

Yechim

Vaqt

Clock inject qilish

Async

Awaitility

DB state

cleanup yoki fresh container

External API

WireMock

Random

seed yoki fixed data

Order dependency

testlar mustaqil bo‘lsin

Parallel conflict

unique data yoki isolated DB


41. CI/CDda testlarni ajratish

Pipeline odatda:

1. Unit tests
2. Slice tests
3. Integration tests
4. Contract tests
5. E2E smoke tests

Maven profile misol:

mvn test
mvn verify -Pintegration

Yaxshi amaliyot:

Pull requestda tez testlar
Main branchda integration/contract
Release oldidan E2E smoke

Lekin critical integration testlar PRda ham yurishi kerak.


42. Test naming

Yomon:

@Test
void test1() {
}

Yaxshi:

@Test
void shouldCreateOrderWhenPaymentSuccessful() {
}

Yoki:

@Test
void createOrder_paymentFails_marksOrderAsFailed() {
}

Nom test maqsadini tushuntirsin.


43. Given / When / Then

Testni o‘qilishi oson bo‘lsin.

@Test
void shouldCreateOrderWhenPaymentSuccessful() {
    // given
    given(paymentClient.charge(any()))
            .willReturn(new PaymentResult("SUCCESS"));

    // when
    OrderDto result = orderService.createOrder(request);

    // then
    assertThat(result.status()).isEqualTo(OrderStatus.PAID);
}

Bu format jamoada testlarni tushunishni osonlashtiradi.


44. Production-grade test checklist

Savol

Ha/Yo‘q

Repositorylar real DBda test qilinganmi?

Migrationlar real DBda yuradimi?

Controller validation testlari bormi?

Security 401/403 holatlari test qilinganmi?

Error response format test qilinganmi?

External HTTP API WireMock bilan test qilinganmi?

Async/event flowlar await bilan test qilinganmi?

Kafka/RabbitMQ critical flow test qilinganmi?

Contract test kerak joyda bormi?

Flaky testlar yo‘qmi?

Testlar CI’da yuradimi?


45. Keng tarqalgan xatolar

Xato

Oqibat

Hamma test @SpringBootTest

Sekin build

Faqat unit test

Integration buglar chiqib ketadi

H2ga haddan tashqari ishonish

PostgreSQL/MySQL buglar ushlanmaydi

External API real chaqirish

Flaky va sekin test

Security test yo‘q

Auth bug productionga chiqadi

Error response test yo‘q

Frontend bilan contract buziladi

Async testda darhol assert

Flaky test

Test data tartibsiz

Testlar bir-biriga ta’sir qiladi

Contract test yo‘q

Microservice API buzilishi kech bilinadi

Mockni haddan tashqari ishlatish

Real wiring/test qiymati kamayadi


46. Interview savollar

Savol 1: @SpringBootTest va @WebMvcTest farqi nima?

Javob:

@SpringBootTest butun application contextni ko‘taradi va integration testlar uchun ishlatiladi. @WebMvcTest faqat web/controller layerni ko‘taradi, service va repositorylar odatda mock qilinadi. @WebMvcTest tezroq va controller validation, mapping, error response testlari uchun mos.


Savol 2: @DataJpaTest nima uchun ishlatiladi?

Javob:

Repository/JPA layerni test qilish uchun. Entity mapping, querylar, repository methodlar, transaction va persistence behaviorni tekshiradi. Production-grade holatda H2 o‘rniga Testcontainers bilan real DB ishlatish yaxshiroq.


Savol 3: Testcontainers nima uchun kerak?

Javob:

Test vaqtida real dependencylarni Docker container sifatida ko‘tarish uchun. Masalan PostgreSQL, Redis, Kafka, RabbitMQ. Bu H2 yoki mockdan ko‘ra productionga yaqinroq test beradi.


Savol 4: WireMock nima qiladi?

Javob:

External HTTP APIlarni fake server orqali mock qiladi. Testda real APIga chiqmasdan, success, error, timeout, invalid response kabi holatlarni nazoratli tekshirish imkonini beradi.


Savol 5: Contract testing nima?

Javob:

Consumer va provider orasidagi API kelishuvni test qilish. Request/response format, status code, fieldlar contract sifatida yoziladi. Provider contractni buzsa build fail bo‘ladi.


Savol 6: Test slice va full context trade-off nima?

Javob:

Slice testlar tez va aniq, lekin butun wiringni tekshirmaydi. Full context testlar real applicationga yaqin, lekin sekinroq va debug qilish qiyinroq. Yaxshi strategiya - ko‘p unit/slice test, kamroq critical integration test.


Savol 7: Flaky test nima?

Javob:

Ba’zan o‘tib, ba’zan yiqiladigan test. Odatda async race, vaqtga bog‘liqlik, shared state, external API, random data yoki test order dependency sabab bo‘ladi. Flaky testlar CI ishonchini buzadi.


47. Qisqa xulosa

Mavzu

Asosiy fikr

Unit test

Tez, business logic

@WebMvcTest

Controller, validation, HTTP response

@DataJpaTest

Repository/JPA

@SpringBootTest

Full integration

Testcontainers

Real DB/broker/cache container

WireMock

External HTTP API mock

@TestConfiguration

Test-specific bean

@MockitoBean

Spring contextda mock bean

Contract testing

Service API kelishuvi

Awaitility

Async testlarni barqaror qilish

Test profile

Test configni ajratish

CI pipeline

Testlarni bosqichma-bosqich yuritish

Eng muhim fikr:

Production-grade testing - "test bor" degani emas. Real dependencylar, security, validation, error response, transaction, external API va async flowlar nazoratli test qilingan bo‘lishi kerak.