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
JsonPathUnit 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? |
|---|---|
| Controller layer |
| JPA/repository layer |
| JSON serialization/deserialization |
| REST client |
| JDBC layer |
Afzallik:
Full context emas
Tezroq
Aniqroq
Kamroq dependency7. @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 boshqachaShuning 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 containerTest 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 statusService 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 fokus17. 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 responseWireMock 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 mumkin22. 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‘ladiSpring 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‘ladiContract 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 API27. Testcontainers + WireMock + SpringBootTest kombinatsiyasi
Real integration test:
Spring Boot app
+ real PostgreSQL container
+ fake Payment API WireMock
+ full contextMisol:
@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 test29. 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 |
|
| 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 kerakBuni Hibernate statistics yoki datasource-proxy bilan tekshirish mumkin.
Maqsad:
N+1 muammo productionga chiqmasinAyniqsa:
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: INFOTestda profile:
@ActiveProfiles("test")
@SpringBootTest
class OrderServiceTest {
}Muhim:
test config productionga yaqin bo‘lsin
lekin external dependencylar test/fake bo‘lsin39. Flaky test nima?
Flaky test - ba’zan o‘tadi, ba’zan yiqiladi.
Sabablar:
Sabab | Misol |
|---|---|
Time dependency |
|
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 |
|
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 testsMaven profile misol:
mvn test
mvn verify -PintegrationYaxshi amaliyot:
Pull requestda tez testlar
Main branchda integration/contract
Release oldidan E2E smokeLekin 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 | 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:
@SpringBootTestbutun application contextni ko‘taradi va integration testlar uchun ishlatiladi.@WebMvcTestfaqat web/controller layerni ko‘taradi, service va repositorylar odatda mock qilinadi.@WebMvcTesttezroq 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 |
| Controller, validation, HTTP response |
| Repository/JPA |
| Full integration |
Testcontainers | Real DB/broker/cache container |
WireMock | External HTTP API mock |
| Test-specific bean |
| 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.