Build tools & testing — Java developer uchun juda muhim bosqich. Chunki real loyihada faqat .java file yozilmaydi. Loyiha:
dependency ishlatadi;
test yozadi;
build qilinadi;
.jarqilib chiqariladi;CI/CD’da avtomatik tekshiriladi;
production’ga deploy qilinadi.
Bu bo‘limga Maven, Gradle basics, JUnit 5, Mockito, code coverage concepts kiritilgan.
1. Build tool nima?
Build tool — Java loyihani boshqaradigan vosita.
U quyidagilarni qiladi:
dependency yuklaydi;
kodni compile qiladi;
testlarni ishga tushiradi;
.jaryoki.warfile yaratadi;project lifecycle’ni boshqaradi;
pluginlar orqali qo‘shimcha ishlarni bajaradi.
Oddiy aytganda:
Build tool — loyihani “yig‘ib beradigan” yordamchi.
Java’da eng mashhur build tool’lar:
Tool | Ko‘p ishlatiladigan joyi |
|---|---|
Maven | Enterprise Java, Spring Boot loyihalar |
Gradle | Android, Kotlin, modern Java loyihalar |
2. Maven
Maven — Java’da eng ko‘p ishlatiladigan build tool’lardan biri.
Maven loyihasida asosiy file:
pom.xmlpom.xml — project konfiguratsiyasi.
Unda:
project nomi;
Java versiyasi;
dependencylar;
pluginlar;
build sozlamalari;
yoziladi.
3. Maven project strukturasi
Standart Maven project:
my-app
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── uz/example/App.java
│ └── resources
│ └── application.properties
└── test
├── java
│ └── uz/example/AppTest.java
└── resourcesTushuntirish:
Papka | Ma’nosi |
|---|---|
| Asosiy Java kod |
| Config filelar |
| Test kodlar |
| Test uchun config/resource |
| Maven konfiguratsiyasi |
4. Oddiy pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>uz.example</groupId>
<artifactId>demo-app</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
</properties>
</project>Bu yerda:
Qism | Ma’nosi |
|---|---|
| Kompaniya yoki package nomi |
| Project nomi |
| Project versiyasi |
| Java versiyasi |
5. Maven dependency
Dependency — loyihaga kerak bo‘ladigan tashqi kutubxona.
Masalan, siz test yozish uchun JUnit ishlatmoqchisiz. Uni projectga qo‘shasiz:
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
</dependencies>Bu degani:
Maven JUnit kutubxonasini internetdan yuklab olib projectga ulaydi.
6. Maven dependency scope
scope dependency qayerda ishlatilishini bildiradi.
Scope | Ma’nosi |
|---|---|
| Default, asosiy kodda ishlatiladi |
| Faqat testlarda ishlatiladi |
| Runtime’da kerak, compile’da emas |
| Server/container beradi, jar ichiga kirmaydi |
JUnit odatda test scope bilan qo‘shiladi:
<scope>test</scope>Chunki JUnit production kodga kerak emas. Faqat test vaqtida kerak.
7. Maven lifecycle
Maven’da build jarayoni bosqichlarga bo‘lingan.
Eng keraklilari:
Command | Vazifasi |
|---|---|
| Kodni compile qiladi |
| Testlarni ishga tushiradi |
|
|
|
|
| Local repository’ga o‘rnatadi |
| Toza build qiladi |
Eng ko‘p ishlatiladigan command:
mvn clean packageBu:
eski buildni o‘chiradi;
kodni compile qiladi;
testlarni ishga tushiradi;
package yaratadi.
8. Maven’da .jar qayerda chiqadi?
Builddan keyin:
target/papka hosil bo‘ladi.
Ichida .jar file bo‘ladi:
target/demo-app-1.0.0.jarIshga tushirish:
java -jar target/demo-app-1.0.0.jarSpring Boot’da ham ko‘pincha shunday ishlatiladi.
9. Gradle
Gradle — Maven’ga alternativa.
Gradle ko‘pincha:
Android;
Kotlin;
multi-module project;
modern backend;
loyihalarda ishlatiladi.
Gradle’da konfiguratsiya odatda:
build.gradleyoki Kotlin DSL’da:
build.gradle.ktsbo‘ladi.
10. Oddiy build.gradle.kts
plugins {
java
}
group = "uz.example"
version = "1.0.0"
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(21))
}
}
repositories {
mavenCentral()
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")
}
tasks.test {
useJUnitPlatform()
}Bu Maven’dagi pom.xmlga o‘xshaydi.
11. Gradle commandlar
Command | Vazifasi |
|---|---|
| Projectni build qiladi |
| Testlarni ishga tushiradi |
| Eski buildni o‘chiradi |
| Spring Boot appni ishga tushiradi |
| Dependency daraxtini ko‘rsatadi |
Windows’da:
gradlew.bat buildLinux/Mac’da:
./gradlew build12. Maven vs Gradle
Mezoni | Maven | Gradle |
|---|---|---|
Config | XML | Groovy/Kotlin DSL |
O‘rganish | Osonroq | Biroz murakkabroq |
Tezlik | Yaxshi | Ko‘pincha tezroq |
Spring Boot | Juda keng | Juda keng |
Android | Kam | Asosiy tool |
Enterprise | Juda ko‘p | Ko‘payib boryapti |
Junior uchun maslahat:
Avval Maven’ni yaxshi tushuning. Keyin Gradle’ga o‘tish osonlashadi.
13. Testing nima?
Testing — kod to‘g‘ri ishlashini avtomatik tekshirish.
Masalan, sizda calculator bor:
public class Calculator {
public int sum(int a, int b) {
return a + b;
}
}Siz har safar qo‘lda tekshirmaysiz:
System.out.println(calculator.sum(2, 3));Buning o‘rniga test yozasiz:
@Test
void shouldReturnSum() {
Calculator calculator = new Calculator();
int result = calculator.sum(2, 3);
assertEquals(5, result);
}Test sizga aytadi:
kod ishlayaptimi;
keyingi o‘zgarish eski logicni buzmadimi;
refactoring xavfsizmi;
bug qaytib kelmadimi.
14. Test turlari
Junior uchun asosiy testlar:
Test turi | Ma’nosi |
|---|---|
Unit test | Bitta class/methodni alohida test qilish |
Integration test | Bir nechta qism birga ishlashini test qilish |
End-to-end test | Butun systemani user kabi test qilish |
Junior bosqichida eng muhimlari:
Unit test + oddiy integration test15. JUnit 5
JUnit 5 — Java’da test yozish uchun eng mashhur framework.
Maven dependency:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>Gradle dependency:
testImplementation("org.junit.jupiter:junit-jupiter:5.10.2")16. Birinchi JUnit test
Production code:
public class Calculator {
public int sum(int a, int b) {
return a + b;
}
}Test code:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class CalculatorTest {
@Test
void shouldReturnSumOfTwoNumbers() {
Calculator calculator = new Calculator();
int result = calculator.sum(2, 3);
assertEquals(5, result);
}
}Bu test:
Calculatoryaratadi;sum(2, 3)chaqiradi;natija
5ekanini tekshiradi.
17. Test nomlash
Yomon:
@Test
void test1() {
}Yaxshi:
@Test
void shouldReturnSumOfTwoNumbers() {
}Yoki:
@Test
void shouldThrowExceptionWhenAmountIsNegative() {
}Test nomidan nima tekshirilayotgani ko‘rinishi kerak.
18. Assertions
JUnit’da tekshirishlar assertions orqali qilinadi.
Eng keraklilari:
Assertion | Ma’nosi |
|---|---|
| Tengligini tekshiradi |
| Teng emasligini tekshiradi |
| True ekanini tekshiradi |
| False ekanini tekshiradi |
| Null ekanini tekshiradi |
| Null emasligini tekshiradi |
| Exception chiqishini tekshiradi |
18.1 assertEquals
assertEquals(5, result);Bu degani:
result 5 ga teng bo‘lishi kerak.18.2 assertTrue
assertTrue(user.isActive());18.3 assertThrows
Production code:
public class PaymentService {
public void pay(int amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Amount must be positive");
}
}
}Test:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertThrows;
class PaymentServiceTest {
@Test
void shouldThrowExceptionWhenAmountIsNegative() {
PaymentService service = new PaymentService();
assertThrows(
IllegalArgumentException.class,
() -> service.pay(-100)
);
}
}Bu test pay(-100) chaqirilganda IllegalArgumentException chiqishini tekshiradi.
19. Test lifecycle annotations
JUnit 5’da foydali annotationlar:
Annotation | Ma’nosi |
|---|---|
| Test method |
| Har bir testdan oldin ishlaydi |
| Har bir testdan keyin ishlaydi |
| Barcha testlardan oldin bir marta |
| Barcha testlardan keyin bir marta |
| Testga chiroyli nom berish |
| Testni vaqtincha o‘chirish |
19.1 @BeforeEach
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class CalculatorTest {
private Calculator calculator;
@BeforeEach
void setUp() {
calculator = new Calculator();
}
@Test
void shouldReturnSum() {
int result = calculator.sum(2, 3);
assertEquals(5, result);
}
@Test
void shouldReturnAnotherSum() {
int result = calculator.sum(10, 20);
assertEquals(30, result);
}
}@BeforeEach har testdan oldin yangi Calculator yaratadi.
20. Arrange Act Assert
Test yozishda yaxshi strukturani ishlating:
Arrange — tayyorlash
Act — ishga tushirish
Assert — tekshirishMisol:
@Test
void shouldReturnSumOfTwoNumbers() {
// Arrange
Calculator calculator = new Calculator();
// Act
int result = calculator.sum(2, 3);
// Assert
assertEquals(5, result);
}Bu testni o‘qishni osonlashtiradi.
21. Unit test
Unit test — bitta class yoki methodni alohida test qilish.
Misol:
public class DiscountService {
public int calculateDiscount(int amount) {
if (amount >= 1_000_000) {
return 20;
}
if (amount >= 500_000) {
return 10;
}
return 0;
}
}Test:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class DiscountServiceTest {
@Test
void shouldReturn20PercentWhenAmountIsGreaterThanOneMillion() {
DiscountService service = new DiscountService();
int discount = service.calculateDiscount(1_200_000);
assertEquals(20, discount);
}
@Test
void shouldReturn10PercentWhenAmountIsGreaterThanFiveHundredThousand() {
DiscountService service = new DiscountService();
int discount = service.calculateDiscount(700_000);
assertEquals(10, discount);
}
@Test
void shouldReturnZeroWhenAmountIsSmall() {
DiscountService service = new DiscountService();
int discount = service.calculateDiscount(100_000);
assertEquals(0, discount);
}
}22. Mockito
Mockito — dependencylarni fake/mock qilib test yozish uchun ishlatiladi.
Masalan, UserService ichida UserRepository bor.
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User findById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User topilmadi"));
}
}Repository interface:
import java.util.Optional;
public interface UserRepository {
Optional<User> findById(Long id);
}Bu service’ni test qilish uchun real database kerak emas. UserRepositoryni mock qilamiz.
23. Mockito dependency
Maven:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>JUnit 5 bilan ishlatish uchun:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>Gradle:
testImplementation("org.mockito:mockito-core:5.11.0")
testImplementation("org.mockito:mockito-junit-jupiter:5.11.0")24. Mockito bilan 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.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void shouldReturnUserWhenUserExists() {
// Arrange
User user = new User(1L, "Ali");
when(userRepository.findById(1L))
.thenReturn(Optional.of(user));
// Act
User result = userService.findById(1L);
// Assert
assertEquals("Ali", result.getName());
}
}Bu yerda:
Qism | Ma’nosi |
|---|---|
| Fake obyekt yaratadi |
| Mocklarni service ichiga inject qiladi |
| Mock qanday javob qaytarishini belgilaydi |
| Mockito’ni JUnit 5 bilan ulaydi |
25. Mockito verify
verify — mock method chaqirilganmi, tekshiradi.
import static org.mockito.Mockito.verify;
@Test
void shouldCallRepositoryFindById() {
User user = new User(1L, "Ali");
when(userRepository.findById(1L))
.thenReturn(Optional.of(user));
userService.findById(1L);
verify(userRepository).findById(1L);
}Bu test userRepository.findById(1L) chaqirilganini tekshiradi.
26. Exception test with Mockito
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;
@Test
void shouldThrowExceptionWhenUserNotFound() {
when(userRepository.findById(99L))
.thenReturn(Optional.empty());
assertThrows(
RuntimeException.class,
() -> userService.findById(99L)
);
}Bu test user topilmasa exception chiqishini tekshiradi.
27. Integration test nima?
Integration test — bir nechta qism birga ishlashini tekshiradi.
Masalan:
Controller + Service;
Service + Repository;
Repository + Database;
REST API + JSON;
Spring Context.
Unit testda dependencylar mock qilinadi.
Integration testda esa realroq muhit ishlatiladi.
28. Spring Boot’da oddiy test turlari
Annotation | Qachon ishlatiladi |
|---|---|
| Butun Spring contextni ko‘taradi |
| Faqat controller layerni test qiladi |
| Repository/JPA testlari uchun |
| Spring context ichida mock bean yaratadi |
Junior bosqichida kamida quyidagilarni bilish kerak:
JUnit + Mockito + @SpringBootTest basic29. Code coverage
Code coverage — testlar kodning necha foizini qamrab olganini ko‘rsatadi.
Masalan:
Coverage: 75%Bu degani testlar kodning 75% qismiga tegib o‘tgan.
Lekin muhim:
100% coverage har doim yaxshi test degani emas.
Yomon test ham coverage beradi:
@Test
void badTest() {
service.doSomething();
}Bu test hech narsani tekshirmaydi. Lekin method ishlagani uchun coverage oshishi mumkin.
Yaxshi test:
@Test
void shouldCalculateTotalPrice() {
int total = service.calculateTotalPrice(100, 2);
assertEquals(200, total);
}Coverage emas, to‘g‘ri assert muhim.
30. JaCoCo
Java’da coverage uchun eng ko‘p ishlatiladigan tool — JaCoCo.
Maven plugin:
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.11</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>Ishga tushirish:
mvn testReport odatda shu joyda chiqadi:
target/site/jacoco/index.html31. Testingda juniorlar qiladigan xatolar
Xato 1: Test yozmaslik
“Qo‘lda tekshirdim” production uchun yetarli emas.
Xato 2: Faqat happy path test qilish
Faqat yaxshi holatni emas, xato holatni ham test qilish kerak.
Masalan:
user topildi;
user topilmadi;
amount manfiy;
input null;
permission yo‘q;
duplicate data.
Xato 3: Test ichida juda ko‘p logic yozish
Yomon:
int expected = 0;
for (Order order : orders) {
expected += order.getAmount();
}
assertEquals(expected, result);Testning o‘zi ham murakkablashib ketmasligi kerak.
Xato 4: Mockni haddan tashqari ko‘p ishlatish
Mockito foydali, lekin hamma narsani mock qilish ham yomon. Ba’zan oddiy real object yaratish yaxshiroq.
Xato 5: Test nomlari tushunarsiz
Yomon:
testUser()
testService()
testMethod1()Yaxshi:
shouldReturnUserWhenUserExists()
shouldThrowExceptionWhenUserNotFound()32. Real mini misol: OrderService test
Production code:
public class OrderService {
public int calculateTotalPrice(int price, int quantity) {
if (price <= 0) {
throw new IllegalArgumentException("Price must be positive");
}
if (quantity <= 0) {
throw new IllegalArgumentException("Quantity must be positive");
}
return price * quantity;
}
}Test:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
class OrderServiceTest {
private final OrderService orderService = new OrderService();
@Test
void shouldCalculateTotalPrice() {
int result = orderService.calculateTotalPrice(100_000, 2);
assertEquals(200_000, result);
}
@Test
void shouldThrowExceptionWhenPriceIsNegative() {
assertThrows(
IllegalArgumentException.class,
() -> orderService.calculateTotalPrice(-100_000, 2)
);
}
@Test
void shouldThrowExceptionWhenQuantityIsZero() {
assertThrows(
IllegalArgumentException.class,
() -> orderService.calculateTotalPrice(100_000, 0)
);
}
}Bu yaxshi test. Chunki:
normal holat bor;
xato holatlar bor;
assert bor;
nomlar tushunarli;
testlar kichik.
33. Real Spring Boot service test
Service:
import java.util.Optional;
public class ProductService {
private final ProductRepository productRepository;
public ProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
public Product getById(Long id) {
return productRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Product topilmadi"));
}
}Repository:
import java.util.Optional;
public interface ProductRepository {
Optional<Product> findById(Long id);
}Product:
public class Product {
private Long id;
private String name;
public Product(Long id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
}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.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class ProductServiceTest {
@Mock
private ProductRepository productRepository;
@InjectMocks
private ProductService productService;
@Test
void shouldReturnProductWhenExists() {
Product product = new Product(1L, "Laptop");
when(productRepository.findById(1L))
.thenReturn(Optional.of(product));
Product result = productService.getById(1L);
assertEquals("Laptop", result.getName());
}
@Test
void shouldThrowExceptionWhenProductNotFound() {
when(productRepository.findById(99L))
.thenReturn(Optional.empty());
assertThrows(
RuntimeException.class,
() -> productService.getById(99L)
);
}
}34. Junior uchun nimani bilish yetarli?
Mavzu | Daraja |
|---|---|
Maven project structure | Majburiy |
| Majburiy |
| Majburiy |
Gradle basic | Kerak |
JUnit 5 | Majburiy |
| Majburiy |
| Kerak |
Mockito | Majburiy |
| Majburiy |
| Kerak |
Code coverage nima | Kerak |
JaCoCo basic | Foydali |
35. Amaliy mashq
Vazifa: Calculator project
Maven project yarating:
calculator-app
├── pom.xml
└── src
├── main
│ └── java
│ └── uz/example/Calculator.java
└── test
└── java
└── uz/example/CalculatorTest.javaCalculator class:
package uz.example;
public class Calculator {
public int sum(int a, int b) {
return a + b;
}
public int divide(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("b cannot be zero");
}
return a / b;
}
}CalculatorTest:
package uz.example;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
class CalculatorTest {
private final Calculator calculator = new Calculator();
@Test
void shouldReturnSum() {
int result = calculator.sum(2, 3);
assertEquals(5, result);
}
@Test
void shouldDivideNumbers() {
int result = calculator.divide(10, 2);
assertEquals(5, result);
}
@Test
void shouldThrowExceptionWhenDividingByZero() {
assertThrows(
IllegalArgumentException.class,
() -> calculator.divide(10, 0)
);
}
}Ishga tushirish:
mvn testBuild qilish:
mvn clean packageXulosa
Build tools & testing real Java development’ning asosiy qismi.
Junior developer quyidagilarni bilishi shart:
mvn clean package
mvn test
./gradlew build
./gradlew testVa test yozishda:
@Test
void shouldDoSomething() {
// Arrange
// Act
// Assert
}Asosiy fikr:
Maven/Gradle projectni boshqaradi;
JUnit test yozadi;
Mockito dependencylarni mock qiladi;
coverage test qamrovini ko‘rsatadi;
yaxshi test production xatolarini kamaytiradi.