Testing & Quality

30.06.2026 | Muallif: Jaxongir a.k.a | Kategoriya: Spring Boot | 25 daqiqa o'qish

Testing & Quality - bu kod "ishlayapti" degani bilan cheklanmaslik. Java developer kodni shunday yozishi kerakki:

1. bug tez topilsin
2. regression kamayadi
3. refactor qilish xavfsiz bo‘ladi
4. production’da kutilmagan xatolar kamayadi
5. code review’dan oson o‘tadi

Bu bo‘limga quyidagilar kiradi: Integration tests with @SpringBootTest, Testcontainers, WireMock, TDD approach, Static analysis: SonarQube, SpotBugs.


1. Testing nima uchun kerak?

Ko‘p juniorlar testni "ortiqcha ish" deb o‘ylaydi. Lekin real loyihada test quyidagilar uchun kerak:

  • eski feature buzilib qolmasligi;

  • yangi developer kodni xavfsiz o‘zgartirishi;

  • biznes qoida avtomatik tekshirilishi;

  • production bug kamayishi;

  • deploymentga ishonch oshishi.

Masalan, order yaratishda qoida bor:

Agar product stock’da yetarli bo‘lmasa, order yaratilmasin.

Buni qo‘lda har safar tekshirish yomon. Test bilan avtomatik tekshiramiz.


2. Test turlari

Backend’da odatda 4 ta asosiy test turi bor:

Test turi

Nimani tekshiradi

Unit test

Bitta class yoki method logic

Integration test

Bir nechta component birga ishlashi

Repository test

DB query va JPA mapping

API/E2E test

HTTP endpoint to‘liq flow


3. Unit Test

Unit test - kichik logicni alohida tekshiradi.

Masalan, discount hisoblash:

public class DiscountService {

    public BigDecimal calculate(BigDecimal amount) {
        if (amount.compareTo(BigDecimal.valueOf(100_000)) >= 0) {
            return amount.multiply(BigDecimal.valueOf(0.1));
        }

        return BigDecimal.ZERO;
    }
}

Test:

import org.junit.jupiter.api.Test;

import java.math.BigDecimal;

import static org.junit.jupiter.api.Assertions.assertEquals;

class DiscountServiceTest {

    private final DiscountService discountService = new DiscountService();

    @Test
    void shouldReturnTenPercentDiscountWhenAmountIsGreaterThan100000() {
        BigDecimal discount = discountService.calculate(BigDecimal.valueOf(200_000));

        assertEquals(BigDecimal.valueOf(20_000.0), discount);
    }

    @Test
    void shouldReturnZeroWhenAmountIsLessThan100000() {
        BigDecimal discount = discountService.calculate(BigDecimal.valueOf(50_000));

        assertEquals(BigDecimal.ZERO, discount);
    }
}

Bu test Spring context ochmaydi. Tez ishlaydi.


4. Unit Test qachon yoziladi?

Unit test quyidagilar uchun yaxshi:

business rule
calculation
validation logic
mapper logic
state transition
utility method
domain method

Masalan:

  • order status NEW → CONFIRMED;

  • discount calculation;

  • payment fee calculation;

  • phone validation;

  • date range validation;

  • permission check.


5. JUnit 5 asoslari

JUnit 5'da asosiy annotationlar:

Annotation

Vazifasi

@Test

Test method

@BeforeEach

Har testdan oldin ishlaydi

@AfterEach

Har testdan keyin ishlaydi

@BeforeAll

Barcha testlardan oldin bir marta

@AfterAll

Barcha testlardan keyin bir marta

@DisplayName

Testga tushunarli nom

@ParameterizedTest

Parametrli test


6. @BeforeEach

class OrderServiceTest {

    private OrderService orderService;

    @BeforeEach
    void setUp() {
        orderService = new OrderService();
    }

    @Test
    void shouldCreateOrder() {
        // test
    }
}

Har testdan oldin yangi holat tayyorlanadi.


7. Assertions

Eng ko‘p ishlatiladigan assertionlar:

assertEquals(expected, actual);
assertTrue(condition);
assertFalse(condition);
assertNotNull(object);
assertNull(object);
assertThrows(Exception.class, () -> method());

Exception test:

@Test
void shouldThrowExceptionWhenStockIsNotEnough() {
    Product product = new Product("Laptop", 1);

    IllegalStateException exception = assertThrows(
            IllegalStateException.class,
            () -> product.decreaseStock(5)
    );

    assertEquals("Stock yetarli emas", exception.getMessage());
}

8. Mockito nima?

Mockito - dependency’larni fake qilish uchun ishlatiladi.

Masalan, OrderService ichida ProductRepository bor:

@Service
public class OrderService {

    private final ProductRepository productRepository;

    public OrderService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    public OrderDto createOrder(Long productId, int quantity) {
        Product product = productRepository.findById(productId)
                .orElseThrow(() -> new RuntimeException("Product topilmadi"));

        product.decreaseStock(quantity);

        return new OrderDto(product.getId(), quantity);
    }
}

Unit testda haqiqiy DB kerak emas. Repository’ni mock qilamiz.

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

class OrderServiceTest {

    private final ProductRepository productRepository = Mockito.mock(ProductRepository.class);
    private final OrderService orderService = new OrderService(productRepository);

    @Test
    void shouldCreateOrder() {
        Product product = new Product(1L, "Laptop", 10);

        when(productRepository.findById(1L))
                .thenReturn(Optional.of(product));

        OrderDto result = orderService.createOrder(1L, 2);

        assertEquals(1L, result.productId());
        assertEquals(2, result.quantity());
    }
}

9. Mockito bilan verify

verify() method chaqirilganini tekshiradi.

verify(productRepository).findById(1L);

Masalan:

@Test
void shouldCallRepository() {
    Product product = new Product(1L, "Laptop", 10);

    when(productRepository.findById(1L))
            .thenReturn(Optional.of(product));

    orderService.createOrder(1L, 2);

    verify(productRepository).findById(1L);
}

Lekin verify()ni haddan tashqari ko‘p ishlatish ham yomon. Test implementationga qattiq bog‘lanib qoladi.


10. Mock qachon kerak?

Mock quyidagilar uchun kerak:

repository
external client
email sender
SMS sender
payment provider
file storage
queue producer

Lekin oddiy domain objectlarni mock qilish shart emas. Real object ishlatish yaxshiroq.

Yomon:

Product product = mock(Product.class);

Yaxshi:

Product product = new Product("Laptop", 10);

11. Unit Test yaxshi yozish qoidasi

Test odatda 3 qismdan iborat:

Arrange - test uchun data tayyorlash
Act - methodni chaqirish
Assert - natijani tekshirish

Misol:

@Test
void shouldDecreaseStock() {
    // Arrange
    Product product = new Product("Laptop", 10);

    // Act
    product.decreaseStock(3);

    // Assert
    assertEquals(7, product.getStock());
}

12. Test nomlash

Yomon:

@Test
void test1() {}

Yaxshi:

@Test
void shouldDecreaseStockWhenQuantityIsAvailable() {}

Yoki:

@Test
@DisplayName("Stock yetarli bo‘lsa product stock kamayishi kerak")
void shouldDecreaseStockWhenQuantityIsAvailable() {}

Test nomidan nimani tekshirayotgani bilinishi kerak.


13. Integration Test

Integration test - bir nechta component birga ishlashini tekshiradi.

Masalan:

Service + Repository + Database
Controller + Service + Validation
Spring Security + JWT filter
Repository + PostgreSQL

Unit test tez, lekin hamma narsani ushlamaydi. Integration test realroq muhit beradi.


14. @SpringBootTest

@SpringBootTest butun Spring contextni ochadi.

@SpringBootTest
class OrderServiceIntegrationTest {

    @Autowired
    private OrderService orderService;

    @Test
    void shouldCreateOrder() {
        // real Spring beanlar bilan test
    }
}

Afzalligi:

  • real beanlar ishlaydi;

  • dependency injection ishlaydi;

  • transaction, validation, eventlar tekshiriladi.

Kamchiligi:

  • sekinroq;

  • context ochiladi;

  • noto‘g‘ri ishlatilsa testlar og‘irlashadi.


15. @DataJpaTest

Repository va JPA mapping test qilish uchun.

@DataJpaTest
class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    void shouldFindByEmail() {
        User user = new User("Ali", "ali@example.com");
        userRepository.save(user);

        Optional<User> result = userRepository.findByEmail("ali@example.com");

        assertTrue(result.isPresent());
    }
}

Bu faqat JPA bilan bog‘liq beanlarni ochadi. @SpringBootTestdan yengilroq.


16. @WebMvcTest

Controller test qilish uchun.

@WebMvcTest(UserController.class)
class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockitoBean
    private UserService userService;

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

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

Bu HTTP layerni test qiladi:

  • URL mapping;

  • request/response;

  • validation;

  • status code;

  • JSON structure.


17. MockMvc

MockMvc real server ko‘tarmasdan HTTP requestni test qiladi.

mockMvc.perform(post("/users")
        .contentType(MediaType.APPLICATION_JSON)
        .content("""
            {
              "name": "Ali",
              "email": "ali@example.com"
            }
            """))
        .andExpect(status().isOk());

Validation error test:

mockMvc.perform(post("/users")
        .contentType(MediaType.APPLICATION_JSON)
        .content("""
            {
              "name": "",
              "email": "wrong-email"
            }
            """))
        .andExpect(status().isBadRequest())
        .andExpect(jsonPath("$.code").value("VALIDATION_ERROR"));

18. Testcontainers

Testcontainers - test paytida Docker container ochib, real dependency bilan test qilish.

Masalan:

  • PostgreSQL;

  • Redis;

  • Kafka;

  • RabbitMQ;

  • MongoDB;

  • Elasticsearch.

Bu juda muhim Middle-level skill.


19. Nega H2 o‘rniga Testcontainers?

Ko‘p loyihalarda test uchun H2 ishlatiladi. Lekin production PostgreSQL bo‘lsa, H2 bilan farqlar chiqishi mumkin.

Masalan:

PostgreSQL syntax boshqacha
JSONB H2'da yo‘q yoki boshqacha
index behavior farq qiladi
transaction isolation farq qiladi
sequence/identity farq qiladi
native query ishlamasligi mumkin

Shuning uchun production PostgreSQL bo‘lsa, testda ham PostgreSQL container ishlatish yaxshi.


20. PostgreSQL Testcontainer misol

Dependency:

testImplementation("org.testcontainers:junit-jupiter")
testImplementation("org.testcontainers:postgresql")

Test:

@Testcontainers
@SpringBootTest
class UserRepositoryIntegrationTest {

    @Container
    static PostgreSQLContainer<?> postgres =
            new PostgreSQLContainer<>("postgres:16")
                    .withDatabaseName("test_db")
                    .withUsername("test")
                    .withPassword("test");

    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
        registry.add("spring.datasource.password", postgres::getPassword);
    }

    @Autowired
    private UserRepository userRepository;

    @Test
    void shouldSaveAndFindUser() {
        User user = new User("Ali", "ali@example.com");

        userRepository.save(user);

        Optional<User> result = userRepository.findByEmail("ali@example.com");

        assertTrue(result.isPresent());
    }
}

Bu test haqiqiy PostgreSQL’da ishlaydi.


21. Redis Testcontainer

@Testcontainers
@SpringBootTest
class RedisCacheIntegrationTest {

    @Container
    static GenericContainer<?> redis =
            new GenericContainer<>("redis:7")
                    .withExposedPorts(6379);

    @DynamicPropertySource
    static void redisProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.data.redis.host", redis::getHost);
        registry.add("spring.data.redis.port", () -> redis.getMappedPort(6379));
    }

    @Test
    void contextLoads() {
    }
}

22. WireMock

WireMock - tashqi HTTP API’larni fake qilish uchun.

Masalan:

Payment provider
SMS provider
Telegram bot API
CRM API
Eskiz SMS API

Test paytida haqiqiy payment providerga request yuborish xavfli. WireMock bilan fake server ochamiz.


23. WireMock misol

Dependency:

testImplementation("org.springframework.cloud:spring-cloud-contract-wiremock")

Test:

@SpringBootTest
@AutoConfigureWireMock(port = 0)
class PaymentClientTest {

    @Autowired
    private PaymentClient paymentClient;

    @Test
    void shouldCreatePayment() {
        stubFor(post(urlEqualTo("/payments"))
                .willReturn(aResponse()
                        .withHeader("Content-Type", "application/json")
                        .withBody("""
                            {
                              "status": "SUCCESS",
                              "transactionId": "trx-123"
                            }
                            """)));

        PaymentResponse response = paymentClient.createPayment(
                new PaymentRequest(BigDecimal.valueOf(100_000))
        );

        assertEquals("SUCCESS", response.status());
        assertEquals("trx-123", response.transactionId());
    }
}

WireMock bilan tekshirish mumkin:

  • request qaysi URLga ketdi;

  • header to‘g‘rimi;

  • body to‘g‘rimi;

  • timeout holati;

  • 500 error holati;

  • invalid response holati.


24. TDD approach

TDD - Test Driven Development.

TDD sikli:

1. Red - avval yiqiladigan test yozamiz
2. Green - test o‘tadigan minimal kod yozamiz
3. Refactor - kodni tozalaymiz

Masalan, talab:

Agar order summasi 100 000 dan katta bo‘lsa, 10% discount berilsin.

Avval test:

@Test
void shouldApplyTenPercentDiscount() {
    DiscountService service = new DiscountService();

    BigDecimal result = service.calculate(BigDecimal.valueOf(200_000));

    assertEquals(BigDecimal.valueOf(20_000.0), result);
}

Keyin minimal kod:

public BigDecimal calculate(BigDecimal amount) {
    return amount.multiply(BigDecimal.valueOf(0.1));
}

Keyin yana test qo‘shamiz:

@Test
void shouldReturnZeroWhenAmountIsLessThan100000() {
    DiscountService service = new DiscountService();

    BigDecimal result = service.calculate(BigDecimal.valueOf(50_000));

    assertEquals(BigDecimal.ZERO, result);
}

Keyin kodni to‘g‘rilaymiz:

public BigDecimal calculate(BigDecimal amount) {
    if (amount.compareTo(BigDecimal.valueOf(100_000)) >= 0) {
        return amount.multiply(BigDecimal.valueOf(0.1));
    }

    return BigDecimal.ZERO;
}

25. TDD qachon foydali?

TDD ayniqsa quyidagilarda foydali:

business rules
calculation
domain model
state machine
validation
edge cases
bug fix

Masalan, bug chiqdi:

Cancelled order payment qilinib ketdi.

Avval test yozamiz:

@Test
void shouldNotPayCancelledOrder() {
    Order order = new Order();
    order.cancel();

    assertThrows(IllegalStateException.class, order::pay);
}

Keyin bugni fix qilamiz. Shu test kelajakda bug qaytmasligini himoya qiladi.


26. Code Coverage

Code coverage - testlar kodning qancha qismini ishlatganini ko‘rsatadi.

Masalan:

Line coverage: 80%
Branch coverage: 65%

Lekin coverage yuqori bo‘lsa ham, test sifati yaxshi degani emas.

Yomon test:

@Test
void test() {
    service.create();
}

Bu faqat method chaqiradi. Natijani tekshirmaydi.

Yaxshi test:

@Test
void shouldCreateOrderWithNewStatus() {
    Order order = service.create();

    assertEquals(OrderStatus.NEW, order.getStatus());
    assertNotNull(order.getCreatedAt());
}

Coverage maqsad emas, signal.


27. Static Analysis

Static analysis - kodni ishga tushirmasdan tekshiradi.

Topishi mumkin:

  • null pointer xavfi;

  • unused code;

  • duplicate code;

  • security issue;

  • code smell;

  • resource leak;

  • noto‘g‘ri equals/hashCode;

  • exception handling muammolari.

Static analysis uchun SonarQube va SpotBugs ishlatiladi.


28. SonarQube

SonarQube - code quality platform.

Tekshiradi:

bugs
vulnerabilities
code smells
coverage
duplications
security hotspots
maintainability
reliability

Masalan, Sonar shunday ogohlantirishi mumkin:

if (user.getName().equals("Ali")) {
}

Agar user.getName() null bo‘lsa, NPE.

Yaxshiroq:

if ("Ali".equals(user.getName())) {
}

29. SpotBugs

SpotBugs - Java bytecode’dan bug patternlarni topadi.

Masalan:

  • null dereference;

  • bad equals;

  • ignored return value;

  • thread-safety issue;

  • resource leak.

Gradle dependency:

plugins {
    id("com.github.spotbugs") version "6.0.0"
}

30. Checkstyle va PMD

Qo‘shimcha quality toollar:

Tool

Vazifasi

Checkstyle

code style qoidalari

PMD

code smell va oddiy buglar

SpotBugs

bytecode asosida bug pattern

SonarQube

umumiy quality dashboard


31. Test Data Builder

Testlarda object yaratish ko‘payib ketadi.

Yomon:

User user = new User(
        "Ali",
        "ali@example.com",
        UserStatus.ACTIVE,
        LocalDateTime.now(),
        true
);

Har testda qaytarilsa, charchatadi.

Yaxshi: test data builder.

public class UserTestBuilder {

    private String name = "Ali";
    private String email = "ali@example.com";
    private UserStatus status = UserStatus.ACTIVE;

    public static UserTestBuilder user() {
        return new UserTestBuilder();
    }

    public UserTestBuilder withEmail(String email) {
        this.email = email;
        return this;
    }

    public UserTestBuilder inactive() {
        this.status = UserStatus.INACTIVE;
        return this;
    }

    public User build() {
        return new User(name, email, status);
    }
}

Ishlatish:

User activeUser = UserTestBuilder.user().build();

User inactiveUser = UserTestBuilder.user()
        .inactive()
        .build();

User customEmailUser = UserTestBuilder.user()
        .withEmail("vali@example.com")
        .build();

32. Testlarda database tozalash

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

Yomon:

1-test user yaratadi
2-test shu user qolganidan yiqiladi

Yechimlar:

@Transactional

@DataJpaTest
@Transactional
class UserRepositoryTest {
}

Test tugaganda rollback bo‘ladi.

@Sql

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

Repository delete

@AfterEach
void cleanUp() {
    userRepository.deleteAll();
}

Katta loyihada Testcontainers + migration + cleanup strategiya aniq bo‘lishi kerak.


33. Flaky Test

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

Sabablar:

vaqtga bog‘liq test
thread/asynchronous code
external API
shared database state
random data
test orderga bog‘liqlik
sleep ishlatish

Yomon:

Thread.sleep(1000);
assertTrue(notificationSent);

Yaxshiroq:

await()
    .atMost(Duration.ofSeconds(5))
    .untilAsserted(() -> assertTrue(notificationSent));

Buning uchun Awaitility ishlatiladi.


34. Async code test qilish

Dependency:

testImplementation("org.awaitility:awaitility")

Misol:

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

    await()
            .atMost(Duration.ofSeconds(5))
            .untilAsserted(() -> {
                verify(notificationService).send(any());
            });
}

Thread.sleep() o‘rniga Awaitility yaxshi.


35. Test piramidasi

Yaxshi loyiha testlari taxminan shunday bo‘ladi:

Ko‘p: Unit tests
O‘rtacha: Integration tests
Kamroq: Full end-to-end tests

Chunki:

  • unit test tez;

  • integration test sekinroq, lekin realroq;

  • E2E test eng sekin va fragile.


36. Qaysi testni qachon yozish kerak?

Holat

Test turi

Business calculation

Unit test

Entity domain method

Unit test

Repository query

@DataJpaTest + Testcontainers

Controller validation

@WebMvcTest

Full API flow

@SpringBootTest + MockMvc

External API client

WireMock

Redis/Kafka/Postgres

Testcontainers

Async event

Awaitility

Security permission

WebMvc/SpringBootTest


37. Real misol: Order yaratish uchun test strategiya

Feature:

User order yaratadi.
Stock yetarli bo‘lsa order CONFIRMED bo‘ladi.
Stock kamayadi.
Agar stock yetarli bo‘lmasa exception chiqadi.

Testlar:

Unit test - Product

@Test
void shouldDecreaseStock() {
    Product product = new Product("Laptop", 10);

    product.decreaseStock(3);

    assertEquals(7, product.getStock());
}

Unit test - stock yetarli emas

@Test
void shouldThrowExceptionWhenStockIsNotEnough() {
    Product product = new Product("Laptop", 2);

    assertThrows(
            IllegalStateException.class,
            () -> product.decreaseStock(5)
    );
}

Integration test - OrderService

@SpringBootTest
@Testcontainers
class OrderServiceIntegrationTest {

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

    @DynamicPropertySource
    static void properties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
        registry.add("spring.datasource.password", postgres::getPassword);
    }

    @Autowired
    private OrderService orderService;

    @Test
    void shouldCreateOrderWhenStockIsEnough() {
        CreateOrderRequest request = new CreateOrderRequest(/* ... */);

        OrderDto result = orderService.create(request);

        assertEquals(OrderStatus.CONFIRMED, result.status());
    }
}

38. Global Exception Handler test

Controller noto‘g‘ri request kelsa 400 Bad Request qaytarishi kerak.

@WebMvcTest(UserController.class)
class UserControllerValidationTest {

    @Autowired
    private MockMvc mockMvc;

    @MockitoBean
    private UserService userService;

    @Test
    void shouldReturnBadRequestWhenEmailInvalid() throws Exception {
        mockMvc.perform(post("/users")
                .contentType(MediaType.APPLICATION_JSON)
                .content("""
                    {
                      "name": "Ali",
                      "email": "wrong-email"
                    }
                    """))
                .andExpect(status().isBadRequest())
                .andExpect(jsonPath("$.code").value("VALIDATION_ERROR"));
    }
}

39. Security test

Admin endpoint faqat admin uchun ochiq bo‘lsin.

@WebMvcTest(AdminController.class)
class AdminControllerSecurityTest {

    @Autowired
    private MockMvc mockMvc;

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

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

40. Testlarda eng ko‘p xatolar

1. Test faqat coverage uchun yoziladi

Yomon:

@Test
void testCreate() {
    service.create(request);
}

Assert yo‘q. Foydasi kam.


2. Hamma narsani mock qilish

Yomon:

Order order = mock(Order.class);
Product product = mock(Product.class);
User user = mock(User.class);

Domain objectlar real bo‘lsin. Tashqi dependencylar mock bo‘lsin.


3. @SpringBootTestni har joyda ishlatish

Yomon:

@SpringBootTest
class DiscountServiceTest {
}

Agar oddiy calculation bo‘lsa, Spring context kerak emas.

Yaxshi:

class DiscountServiceTest {
    private final DiscountService service = new DiscountService();
}

4. Testlar bir-biriga bog‘liq

Yomon:

test1 user yaratadi
test2 shu user bor deb kutadi

Har test mustaqil bo‘lishi kerak.


5. Real external API chaqirish

Yomon:

paymentClient.pay(realCard);

Testda real payment, real SMS, real email ishlatish xavfli.

Yaxshi:

WireMock
MockBean
Fake implementation

41. CI/CD’da test

Real loyihada testlar pipeline’da ishlaydi:

git push
   ↓
build
   ↓
unit tests
   ↓
integration tests
   ↓
static analysis
   ↓
docker image
   ↓
deploy

Agar test yiqilsa, deploy to‘xtaydi.

Bu productionni himoya qiladi.


42. Gradle’da test commandlar

./gradlew test

SpotBugs:

./gradlew spotbugsMain

Checkstyle:

./gradlew checkstyleMain

Barchasi:

./gradlew clean build

43. Pull Request quality checklist

PR ochishdan oldin:

1. Unit testlar o‘tdimi?
2. Integration testlar o‘tdimi?
3. Yangi business rule uchun test bormi?
4. Validation error test qilinganmi?
5. Security permission test qilinganmi?
6. Static analysis xatolari yo‘qmi?
7. Code duplication yo‘qmi?
8. Loglar to‘g‘rimi?
9. Sensitive data logga chiqmayaptimi?
10. Testlar flaky emasmi?

44. Java Developer uchun minimal checklist

Testing & Quality bo‘yicha biz quyidagilarni bilishimiz kerak:

JUnit 5
Mockito
unit test
integration test
@SpringBootTest
@DataJpaTest
@WebMvcTest
MockMvc
Testcontainers
WireMock
Awaitility
TDD asoslari
code coverage
SonarQube
SpotBugs
Checkstyle/PMD
test data builder
flaky test sabablari
CI’da test ishlashi

45. Interview savollari

Unit test va integration test farqi?

Unit test bitta kichik logicni alohida tekshiradi. Integration test bir nechta component birga ishlashini tekshiradi.

Mock nima?

Real dependency o‘rniga test uchun fake object.

Mockito qachon ishlatiladi?

Repository, external API client, email sender kabi dependencylarni fake qilish uchun.

@SpringBootTest nima qiladi?

Butun Spring contextni ochadi va real beanlar bilan test qilish imkonini beradi.

@DataJpaTest nima uchun?

Repository va JPA mapping testlari uchun.

Testcontainers nima?

Test paytida Docker containerlarda real dependency, masalan PostgreSQL yoki Redis, ishga tushirib beradi.

WireMock nima?

Tashqi HTTP API’larni fake qilish uchun ishlatiladi.

TDD nima?

Avval test yozish, keyin testdan o‘tadigan kod yozish, so‘ng refactor qilish yondashuvi.

Code coverage 100% bo‘lsa, kod sifatli deganimi?

Yo‘q. Coverage faqat testlar kodni necha foiz ishlatganini ko‘rsatadi. Testlar assert qilmasa, coverage foydasiz bo‘lishi mumkin.

Flaky test nima?

Ba’zida o‘tib, ba’zida yiqiladigan ishonchsiz test.


Qisqa xulosa

Testing & Quality - Java developer uchun majburiy skill.

Junior ko‘pincha shunday qiladi:

kod yozdim
Postman’da tekshirdim
ishladi

Middle esa shunday o‘ylaydi:

business rule test bilan himoyalanganmi?
repository query real DBda ishlaydimi?
validation response to‘g‘rimi?
external API WireMock bilan test qilinganmi?
Testcontainers orqali PostgreSQL tekshirildimi?
Sonar/SpotBugs xatolari yo‘qmi?
CI pipeline’da test o‘tadimi?

Eng muhim 5 ta joy:

1. Unit test - business logic uchun
2. Integration test - Spring + DB uchun
3. Testcontainers - real dependency uchun
4. WireMock - external API uchun
5. Static analysis - code quality uchun