ЛЕКЦ 03: ПРОГРАМ ХАНГАМЖИЙН ТЕСТЧИЛЭЛ (Software Testing)
Хичээлийн зорилго: Програм хангамжийн тестчилэлийн суурь ойлголт, аргачлалууд, түвшнүүд, JUnit фреймворк ашиглан тест бичих чадвар эзэмшүүлэх.
Хамрах хүрээ: Тестчилэлийн түвшнүүд, Unit Testing, Integration Testing, TDD, JUnit 5, Code Coverage, тест стратегиуд.
ХЭСЭГ 1: ОНОЛЫН СУУРЬ (Theory & Foundations)
1.1 Тестчилэл гэж юу вэ?
Програм хангамжийн тестчилэл (Software Testing) гэдэг нь програм зөв ажиллаж байгаа эсэхийг шалгах, алдааг (bug) олох, чанарыг баталгаажуулах процесс юм.
🔑 IEEE тодорхойлолт: "Тестчилэл нь програмыг хүлээгдэж буй үр дүнтэй нь харьцуулж, зөрүүг олох процесс."
Тестчилэл яагаад чухал вэ?
Барилга барьж дууссаны дараа газар хөдлөлтийн шалгалт хийдэг шиг, програм хангамж мөн хэрэглэгчид хүрэхээс өмнө сайтар шалгагдах ёстой.
Бодит жишээ — Алдааны үнэ:
| Алдааг олсон үе шат | Засах зардал (харьцангуй) |
|---|---|
| Шаардлага тодорхойлолт | 1× |
| Дизайн | 5× |
| Кодчилол | 10× |
| Тестчилэл | 20× |
| Хэрэглэгчид хүрсний дараа | 100× |
💡 Зүйрлэл: Хувцас оёхдоо хэмжилт алдвал эхэндээ засахад хялбар. Бэлэн хувцас болсны дараа засвар хийхэд их цаг, мөнгө шаардагдана. Код мөн адил.
Тестчилэлийн гол зорилгууд:
- Алдаа олох — Код дахь буруу логик, бичлэгийн алдааг олж засах
- Чанар баталгаажуулах — Шаардлагын дагуу зөв ажиллаж байгааг батлах
- Итгэлцэл бий болгох — Програмд итгэж болно гэсэн баталгаа
- Регрессийн хамгаалалт — Шинэ код нэмэхэд хуучин функц эвдрэхгүй байх
- Баримтжуулалт — Тест нь кодын зан төлөвийн "амьд" баримт бичиг
1.2 Тестчилэлийн суурь зарчмууд (7 зарчим — ISTQB)
ISTQB (International Software Testing Qualifications Board) нь 7 суурь зарчмыг тодорхойлсон:
Зарчим 1: Тестчилэл нь алдаа байгааг харуулдаг, алдаагүйг биш
Зүйрлэл: Шөнийн харанхуйд гэрлээр гэрийг шалгахад бөөс олдсон бол — бөөс БАЙНА гэсэн үг. Олдоогүй бол — БАЙХГҮЙ гэсэн үг БИШ, зүгээр олдоогүй гэсэн үг.
Тестчилэл нь алдааг олж чадна, гэхдээ алдаа огт байхгүй гэдгийг батлах чадваргүй. 100 тест дамжсан ч 101 дэх тохиолдолд алдаа гарч болно.
Зарчим 2: Бүрэн тестчилэл боломжгүй (Exhaustive testing is impossible)
Зүйрлэл: Хэрэв нэг функц 3 параметр авдаг, параметр бүр 100 утга авч болдог бол: 100 × 100 × 100 = 1,000,000 тохиолдол. Бүгдийг тестлэх боломжгүй!
Бүх оролт, бүх нөхцөлийг тестлэх нь бараг боломжгүй. Тиймээс эрсдэлд суурилсан тест стратеги ашиглана.
Зарчим 3: Эрт тестлэх (Early testing)
Зүйрлэл: Хорт хавдрыг эрт оношлох тусмаа эдгэрэх магадлал өндөр. Алдааг эрт олох тусмаа засах зардал бага.
Тестчилэлийг зөвхөн кодчилол дууссаны дараа биш, шаардлага, дизайны шатнаас эхлэх ёстой.
Зарчим 4: Алдааны бөөгнөрөл (Defect clustering)
Зүйрлэл: "Парето зарчим" — Алдааны 80% нь кодын 20%-д байдаг.
Програмын нарийн төвөгтэй, олон удаа өөрчлөгдсөн хэсгүүдэд алдаа бөөгнөрдөг. Тэр хэсгүүдэд анхаарал төвлөрүүлэх ёстой.
Зарчим 5: Хортон шавжны эм (Pesticide paradox)
Зүйрлэл: Нэг л хортон шавжны эмийг давтан хэрэглэвэл шавж дасдаг. Ижил тестийг давтвал шинэ алдаа олдохгүй.
Тестийг байнга шинэчлэх, шинэ тохиолдлууд нэмэх шаардлагатай. Хуучин тестээр шинэ алдаа олдохгүй.
Зарчим 6: Тестчилэл нь контекстаас хамаарна
Зүйрлэл: Нисэх онгоцны програм ба мобайл тоглоомын тест адилхан биш. Нисэх онгоцны программ алдаа гаргавал хүмүүсийн амь насанд аюултай, тоглоом алдаа гаргавал зүгээр дахин эхэлнэ.
Тестийн стратеги нь програмын төрөл, эрсдэл, зорилго-оос хамаарна.
Зарчим 7: Алдаагүй гэсэн төөрөгдөл (Absence-of-errors fallacy)
Зүйрлэл: 0 алдаатай програм ч хэрэглэгчийн шаардлагад нийцэхгүй байж болно.
Алдаагүй програм ≠ Зөв програм. Програм хэрэглэгчийн хэрэгцээг хангаж чадаж байгаа эсэх нь чухал.
1.3 Тестчилэлийн түвшнүүд (Testing Levels)
Тестчилэл нь пирамид бүтэцтэй — доороос дээш:
▲
/ \ ← E2E Testing (Системийн бүрэн тест)
/ \ Удаан, цөөн
/ \
/ Integra-\ ← Integration Testing (Нэгтгэлийн тест)
/ tion \ Дунд зэрэг
/ \
/ Unit Testing \ ← Unit Testing (Нэгж тест)
/ \ Хурдан, маш олон
/___________________\
1.3.1 Unit Testing (Нэгж тест)
Тодорхойлолт: Кодын хамгийн ЖИЖИГ нэгжийг (метод, функц) тусад нь шалгах.
Зүйрлэл: Машинд суурилуулахаас өмнө мотор, тоормос, гэрэл тус бүрийг ТУСАД НЬ шалгах. Мотор зөв ажиллаж байна уу? Тоормос зөв зогсоож байна уу?
Онцлог:
- Хамгийн хурдан — миллисекунд хугацаанд ажиллана
- Хамгийн олон — тестийн 70-80% нь unit тест
- Хамгийн хямд — олж засахад хялбар
- Хөгжүүлэгч бичдэг — код бичсэн хүн бичнэ
// Unit тестийн жишээ — Calculator классын нэмэх методыг тестлэх
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
@Test
void testAdd() {
Calculator calc = new Calculator();
assertEquals(5, calc.add(2, 3)); // 2 + 3 = 5 байх ёстой
}
@Test
void testAddNegative() {
Calculator calc = new Calculator();
assertEquals(-1, calc.add(2, -3)); // 2 + (-3) = -1 байх ёстой
}
@Test
void testAddZero() {
Calculator calc = new Calculator();
assertEquals(0, calc.add(0, 0)); // 0 + 0 = 0 байх ёстой
}
}
1.3.2 Integration Testing (Нэгтгэлийн тест)
Тодорхойлолт: Олон модуль, компонентыг НЭГТГЭЖ шалгах. Модулиуд хоорондоо зөв харилцаж байгаа эсэхийг баталгаажуулах.
Зүйрлэл: Мотор, тоормос, хурдны хайрцаг тус бүрдээ зөв ажилладаг ч хамтдаа зөв ажиллаж байгаа эсэхийг шалгах. Мотор хурдны хайрцагтай зөв холбогдож байна уу?
Нэгтгэлийн тестийн аргууд:
| Арга | Тайлбар | Зүйрлэл |
|---|---|---|
| Big Bang | Бүх модулийг нэг дор нэгтгэж тестлэх | Бүх эд ангийг нэг дор угсарч шалгах |
| Top-Down | Дээрээс доош нэгтгэж тестлэх | Дээврээс эхэлж барилга барих |
| Bottom-Up | Доороос дээш нэгтгэж тестлэх | Суурьнаас эхэлж барилга барих |
| Sandwich | Top-Down + Bottom-Up хослуулах | Дундаас хоёр зүгт зэрэг барих |
// Integration тестийн жишээ — UserService ба Database хамтран ажиллаж байгааг шалгах
class UserServiceIntegrationTest {
@Test
void testRegisterAndFindUser() {
Database db = new Database("test.db");
UserService service = new UserService(db);
// Хэрэглэгч бүртгэх
service.register("Бат", "bat@email.com");
// Бүртгэсэн хэрэглэгчийг олох
User found = service.findByEmail("bat@email.com");
assertNotNull(found); // Олдсон байх ёстой
assertEquals("Бат", found.getName()); // Нэр тохирч байх ёстой
}
}
1.3.3 System Testing (Системийн тест)
Тодорхойлолт: Бүхэл системийг шаардлагын дагуу ажиллаж байгаа эсэхийг шалгах.
Зүйрлэл: Бүрэн угсарсан машиныг замд гаргаж жолоодож шалгах — бүх зүйл хамтдаа зөв ажиллаж байна уу?
1.3.4 Acceptance Testing (Хүлээн авах тест)
Тодорхойлолт: Хэрэглэгч / захиалагч системийг хүлээн авахын өмнө хийх тест.
Зүйрлэл: Машин худалдан авагч жолоодож туршаад "тийм, энэ машин надад тохирч байна" гэж хэлэх.
Төрлүүд:
- Alpha тест — Хөгжүүлэгч байгууллагын дотор
- Beta тест — Бодит хэрэглэгчдэд тарааж шалгуулах
- UAT (User Acceptance Testing) — Захиалагч шалгах
1.4 Тестийн аргачлалууд (Testing Techniques)
1.4.1 Хар хайрцагны тест (Black-Box Testing)
Тодорхойлолт: Кодын дотоод бүтцийг МЭДЭХГҮЙГЭЭР, зөвхөн оролт → гаралтыг шалгах.
Зүйрлэл: Вендинг машин. Мөнгө хийж, товч дарна → Бүтээгдэхүүн гарна. Дотор нь яаж ажиллаж байгааг мэдэх шаардлагагүй.
Техникүүд:
а) Эквивалент ангилал (Equivalence Partitioning)
Оролтыг "ижил зан төлөвтэй" бүлгүүдэд хуваана. Бүлэг бүрээс нэг утга тестлэхэд хангалттай.
Жишээ: Насны баталгаажуулалт (18-65 зөвшөөрөгддөг)
├── Бүлэг 1: < 18 (буруу) → Тест: 10
├── Бүлэг 2: 18-65 (зөв) → Тест: 30
└── Бүлэг 3: > 65 (буруу) → Тест: 70
б) Хил заагийн шинжилгээ (Boundary Value Analysis)
Хилийн утгууд дээр алдаа хамгийн их гардаг → Хилийн утгуудыг онцгойлон тестлэх.
Жишээ: Насны баталгаажуулалт (18-65)
Тестлэх утгууд: 17, 18, 19, 64, 65, 66
↑ ↑ ↑ ↑
Хилийн утгууд дээр алдаа их гардаг!
в) Шийдвэрийн хүснэгт (Decision Table)
Олон нөхцөлийн хослолуудыг хүснэгтээр тестлэх:
| Нөхцөл | Тест 1 | Тест 2 | Тест 3 | Тест 4 |
|-----------------|--------|--------|--------|--------|
| Нас >= 18 | Тийм | Тийм | Үгүй | Үгүй |
| Жолооны үнэмлэх | Тийм | Үгүй | Тийм | Үгүй |
| Машин жолоодох | ✅ Зөв | ❌ Буруу | ❌ Буруу | ❌ Буруу |
1.4.2 Цагаан хайрцагны тест (White-Box Testing)
Тодорхойлолт: Кодын дотоод бүтцийг МЭДЭЖ, бүх замналуудыг шалгах.
Зүйрлэл: Машины механик моторыг задалж, дотоод эд анги бүрийг шалгах.
Техникүүд:
а) Мэдэгдлийн хамралт (Statement Coverage)
Кодын бүх мэдэгдэл (statement) дор хаяж 1 удаа ажиллаж байгааг шалгах.
// Шалгах код
public String getGrade(int score) {
if (score >= 90) { // Мэдэгдэл 1
return "A"; // Мэдэгдэл 2
} else if (score >= 80) { // Мэдэгдэл 3
return "B"; // Мэдэгдэл 4
} else {
return "F"; // Мэдэгдэл 5
}
}
// 100% statement coverage-д:
// Тест 1: score = 95 → "A" (Мэдэгдэл 1, 2)
// Тест 2: score = 85 → "B" (Мэдэгдэл 3, 4)
// Тест 3: score = 50 → "F" (Мэдэгдэл 5)
б) Салаалтын хамралт (Branch Coverage)
Бүх if/else салаалтын TRUE ба FALSE замыг тестлэх.
в) Замналын хамралт (Path Coverage)
Кодын бүх боломжит замналуудыг тестлэх — хамгийн иж бүрэн гэхдээ хамгийн их хүчин чармайлт шаарддаг.
1.4.3 Саарал хайрцагны тест (Grey-Box Testing)
Хар + Цагаан хайрцагны хослол. Дотоод бүтцийн ЗАРИМ мэдлэгтэй байж тестлэх.
Зүйрлэл: Машины механик мотороо мэддэг (цагаан) гэхдээ дотор бүрэн задлахгүйгээр, гаднаас оношлох (хар). Хоёрыг хослуулах.
1.5 Test-Driven Development (TDD)
TDD нь "Тестээ ЭХЛЭЭД бич, дараа нь кодоо бич" гэсэн хөгжүүлэлтийн арга.
TDD-ийн 3 алхам (Red-Green-Refactor):
┌─────────┐
│ 🔴 RED │ ← 1. Шинэ тест бич (тест FAIL болно)
└────┬────┘
│
┌────▼────┐
│ 🟢 GREEN│ ← 2. Тестийг дамжуулах ХАМГИЙН БАГА кодыг бич
└────┬────┘
│
┌────▼─────┐
│🔵REFACTOR│ ← 3. Кодыг цэвэрлэ, сайжруул (тест дахин дамждаг)
└────┬─────┘
│
└─────── 🔄 Давтана
TDD-ийн бодит жишээ: FizzBuzz
Даалгавар: 1-100 хүртэлх тоонуудыг хэвлэх. 3-д хуваагддаг бол "Fizz", 5-д хуваагддаг бол "Buzz", хоёуланд нь хуваагддаг бол "FizzBuzz".
Алхам 1 — 🔴 RED: Тест бичих
@Test
void testFizzBuzzOf1() {
assertEquals("1", FizzBuzz.convert(1)); // 1 → "1"
}
Алхам 2 — 🟢 GREEN: Хамгийн бага кодыг бичих
class FizzBuzz {
public static String convert(int number) {
return String.valueOf(number); // Зүгээр тоог String болгох
}
}
Алхам 3 — 🔴 RED: Шинэ тест нэмэх
@Test
void testFizzBuzzOf3() {
assertEquals("Fizz", FizzBuzz.convert(3)); // 3 → "Fizz"
}
Алхам 4 — 🟢 GREEN: Кодыг өргөтгөх
class FizzBuzz {
public static String convert(int number) {
if (number % 3 == 0) return "Fizz";
return String.valueOf(number);
}
}
Алхам 5 — 🔴 RED → 🟢 GREEN: 5-д хуваагддаг
@Test
void testFizzBuzzOf5() {
assertEquals("Buzz", FizzBuzz.convert(5)); // 5 → "Buzz"
}
// Код:
class FizzBuzz {
public static String convert(int number) {
if (number % 3 == 0 && number % 5 == 0) return "FizzBuzz";
if (number % 3 == 0) return "Fizz";
if (number % 5 == 0) return "Buzz";
return String.valueOf(number);
}
}
TDD-ийн давуу ба сул талууд:
| Давуу тал | Сул тал |
|---|---|
| Алдааг эрт олдог | Эхэндээ удаан |
| Кодын чанар сайжирдаг | Сурах муруй өндөр |
| Дахин засварлахад (refactor) итгэлтэй | Бүх нөхцөлд тохирохгүй (UI тест) |
| Баримтжуулалт болдог | Тест maintenance шаардагддаг |
| Дизайныг сайжруулдаг | Хэт нарийн тестчилэлд хүргэж болно |
1.6 JUnit 5 фреймворк
JUnit нь Java-ийн хамгийн алдартай unit тестийн фреймворк. JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage.
JUnit 5-ийн гол аннотациуд:
| Аннотаци | Зорилго | Зүйрлэл |
|---|---|---|
@Test | Метод нь тест гэдгийг заах | "Энэ бол шалгалт" гэсэн шошго |
@BeforeEach | Тест бүрийн өмнө ажиллах | Шалгалтын өмнө ширээ цэвэрлэх |
@AfterEach | Тест бүрийн дараа ажиллах | Шалгалтын дараа ширээ цэвэрлэх |
@BeforeAll | Бүх тестийн өмнө 1 удаа ажиллах | Шалгалтын өрөө бэлтгэх |
@AfterAll | Бүх тестийн дараа 1 удаа ажиллах | Шалгалтын өрөө хаах |
@DisplayName | Тестийн нэрийг тодорхойлох | Шалгалтын асуултын гарчиг |
@Disabled | Тестийг түр хаах | "Энэ асуултыг алгас" |
@ParameterizedTest | Олон утгаар тестлэх | Олон оюутнаар ижил шалгалт авах |
@RepeatedTest | Тестийг олон удаа давтах | Шалгалтыг давтан авах |
JUnit 5-ийн гол assert методууд:
// Тэнцүү эсэх
assertEquals(expected, actual); // expected == actual
assertNotEquals(unexpected, actual); // unexpected != actual
// Null эсэх
assertNull(object); // object == null
assertNotNull(object); // object != null
// Boolean
assertTrue(condition); // condition == true
assertFalse(condition); // condition == false
// Exception шалгах
assertThrows(Exception.class, () -> {
// Exception үүсгэх код
});
// Хугацааны хязгаар
assertTimeout(Duration.ofSeconds(2), () -> {
// 2 секундэд дуусах ёстой код
});
// Массив тэнцүү эсэх
assertArrayEquals(expectedArray, actualArray);
JUnit 5 бүрэн жишээ: BankAccount тест
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
// ===== Тестлэх класс =====
class BankAccount {
private String owner;
private double balance;
public BankAccount(String owner, double initialBalance) {
if (initialBalance < 0) {
throw new IllegalArgumentException("Анхны үлдэгдэл сөрөг байж болохгүй");
}
this.owner = owner;
this.balance = initialBalance;
}
public void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Нэмэх дүн 0-ээс их байх ёстой");
}
balance += amount;
}
public void withdraw(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Авах дүн 0-ээс их байх ёстой");
}
if (amount > balance) {
throw new IllegalStateException("Үлдэгдэл хүрэлцэхгүй байна");
}
balance -= amount;
}
public double getBalance() { return balance; }
public String getOwner() { return owner; }
}
// ===== Тест класс =====
class BankAccountTest {
private BankAccount account;
@BeforeEach
void setUp() {
// Тест бүрийн өмнө шинэ данс үүсгэнэ
account = new BankAccount("Бат", 10000);
}
@Test
@DisplayName("Данс үүсгэхэд үлдэгдэл зөв байх")
void testInitialBalance() {
assertEquals(10000, account.getBalance());
assertEquals("Бат", account.getOwner());
}
@Test
@DisplayName("Мөнгө нэмэхэд үлдэгдэл нэмэгдэх")
void testDeposit() {
account.deposit(5000);
assertEquals(15000, account.getBalance()); // 10000 + 5000
}
@Test
@DisplayName("Мөнгө авахад үлдэгдэл хасагдах")
void testWithdraw() {
account.withdraw(3000);
assertEquals(7000, account.getBalance()); // 10000 - 3000
}
@Test
@DisplayName("Үлдэгдэлээс их мөнгө авахад алдаа гарах")
void testWithdrawInsufficientFunds() {
assertThrows(IllegalStateException.class, () -> {
account.withdraw(50000); // 10000-аас их → Алдаа!
});
}
@Test
@DisplayName("Сөрөг дүн нэмэхэд алдаа гарах")
void testDepositNegativeAmount() {
assertThrows(IllegalArgumentException.class, () -> {
account.deposit(-1000); // Сөрөг дүн → Алдаа!
});
}
@Test
@DisplayName("Сөрөг анхны үлдэгдлээр данс үүсгэхэд алдаа гарах")
void testNegativeInitialBalance() {
assertThrows(IllegalArgumentException.class, () -> {
new BankAccount("Болд", -5000); // Сөрөг → Алдаа!
});
}
@Test
@DisplayName("Олон удаа мөнгө нэмж авахад зөв тооцоолох")
void testMultipleTransactions() {
account.deposit(5000); // 10000 + 5000 = 15000
account.withdraw(3000); // 15000 - 3000 = 12000
account.deposit(1000); // 12000 + 1000 = 13000
assertEquals(13000, account.getBalance());
}
}
1.7 Code Coverage (Кодын хамралт)
Code Coverage гэдэг нь тестээр кодын хэдэн хувь хамрагдсан бэ гэдгийг хэмждэг.
Зүйрлэл: Гэрийн шалгалтаар бүх өрөө шалгагдсан уу? 10 өрөөнөөс 8-ыг шалгасан бол 80% хамралт.
Хамралтын төрлүүд:
| Төрөл | Тайлбар | Жишээ |
|---|---|---|
| Statement Coverage | Кодын мөр бүр ажиллаж байна уу | 20 мөрнөөс 18 ажилласан → 90% |
| Branch Coverage | if/else бүр хоёр чиглэлд тестлэгдсэн үү | 10 салаанаас 8 тестлэгдсэн → 80% |
| Method Coverage | Метод бүр дуудагдсан уу | 5 методоос 5 дуудагдсан → 100% |
| Line Coverage | Мөр бүр ажиллаж байна уу | Statement Coverage-тэй төстэй |
Хамралтын зөвлөмж:
| Хамралтын түвшин | Үнэлгээ |
|---|---|
| < 50% | ❌ Маш муу — олон алдаа нуугдаж байна |
| 50-70% | ⚠️ Дунд зэрэг — сайжруулах хэрэгтэй |
| 70-85% | ✅ Сайн — ихэнх төслийн стандарт |
| 85-95% | ✅ Маш сайн — чухал системүүдэд зөвлөгддөг |
| 100% | ⚠️ Хэтэрхий — 100% хамралт ≠ 100% алдаагүй |
⚠️ Анхааруулга: 100% coverage нь алдаагүй гэсэн үг биш! Тест нь зөв зүйлийг шалгаж байгаа эсэх (test quality) нь coverage-ээс чухал.
1.8 Тестийн сайн практикууд (Best Practices)
AAA загвар (Arrange-Act-Assert):
@Test
void testDiscount() {
// ARRANGE — Бэлтгэх
Product product = new Product("Ном", 20000);
DiscountService service = new DiscountService();
// ACT — Үйлдэл хийх
double discountedPrice = service.applyDiscount(product, 10);
// ASSERT — Шалгах
assertEquals(18000, discountedPrice); // 20000 - 10% = 18000
}
FIRST зарчмууд:
| Зарчим | Англи | Монгол тайлбар |
|---|---|---|
| F | Fast | Тест ХУРДАН ажиллах ёстой |
| I | Independent | Тестүүд бие биенээсээ ХАМААРАЛГҮЙ |
| R | Repeatable | Хэзээ ч ажиллуулсан ИЖИЛ үр дүн |
| S | Self-validating | Тест ӨӨрӨӨ ЗӨРҮҮ/ДАМЖСАН гэж хариулах |
| T | Timely | Тестийг ЦАГТ НЬ бичих (кодтой зэрэг) |
Нэг тест — нэг зүйл шалгах:
// ❌ БУРУУ — олон зүйл нэг тестэд
@Test
void testEverything() {
assertEquals(5, calc.add(2, 3));
assertEquals(6, calc.multiply(2, 3)); // Хоёр өөр функц нэг тестэд
assertNotNull(calc.toString());
}
// ✅ ЗӨӨВ — тус тусдаа
@Test
void testAdd() {
assertEquals(5, calc.add(2, 3));
}
@Test
void testMultiply() {
assertEquals(6, calc.multiply(2, 3));
}
Тестийн нэрлэх дүрэм:
// Загвар: methodName_condition_expectedResult
@Test void add_twoPositiveNumbers_returnsSum() { ... }
@Test void withdraw_insufficientBalance_throwsException() { ... }
@Test void login_invalidPassword_returnsFalse() { ... }
1.9 Mock ба Stub
Тестлэх объект бусад объектоос хамааралтай бол Mock ба Stub ашиглана.
Зүйрлэл: Жүжигчин бодит дайсантай биш, хиймэл манекентай дасгал хийдэг шиг — тест бодит мэдээллийн сантай биш, хиймэл объекттой ажиллана.
Stub vs Mock:
| Stub | Mock | |
|---|---|---|
| Зорилго | Бэлэн хариу буцаах | Зан төлөвийг шалгах |
| Зүйрлэл | Автомат хариулагч машин | Хэн юу хэлснийг бичиж авдаг нарийн бичгийн дарга |
| Шалгах зүйл | Гаралтын утга | Метод дуудагдсан эсэх, хэдэн удаа дуудагдсан |
// Stub жишээ — Тогтмол хариу буцаадаг
class StubEmailService implements EmailService {
@Override
public boolean send(String to, String message) {
return true; // Үргэлж амжилттай гэж буцаана
}
}
// Mock жишээ (Mockito ашиглан)
@Test
void testUserRegistration() {
EmailService mockEmail = mock(EmailService.class); // Mock үүсгэх
UserService service = new UserService(mockEmail);
service.register("Бат", "bat@email.com");
// Баталгаажуулах: send метод 1 удаа дуудагдсан уу?
verify(mockEmail, times(1)).send(eq("bat@email.com"), anyString());
}
1.10 Тестийн төрлүүд (Functional vs Non-Functional)
Функциональ тест (Functional Testing):
Систем юу хийдэг-ийг шалгана.
| Төрөл | Тайлбар |
|---|---|
| Unit Test | Нэгж функцийн шалгалт |
| Integration Test | Модулиудын хамтын ажиллагаа |
| System Test | Бүхэл системийн шалгалт |
| Acceptance Test | Хэрэглэгчийн шаардлага хангаж буй эсэх |
| Regression Test | Шинэ код хуучин функцийг эвдсэн эсэх |
| Smoke Test | Системийн суурь функцүүд ажиллаж байна уу (хурдан шалгалт) |
Функциональ бус тест (Non-Functional Testing):
Систем яаж хийдэг-ийг шалгана.
| Төрөл | Тайлбар | Зүйрлэл |
|---|---|---|
| Performance Test | Хурд, хариу өгөх хугацаа | Машин хэр хурдан вэ? |
| Load Test | Ачаалал дор ажиллагаа | 1000 хүн нэг зэрэг нэвтэрвэл? |
| Stress Test | Хязгаарын ачаалал | Машин хамгийн ихдээ хэр хурдалж чадах вэ? |
| Security Test | Аюулгүй байдал | Хаалга, цонх түгжигдсэн үү? |
| Usability Test | Хэрэглэхэд хялбар эсэх | Машин жолоодоход хялбар уу? |
| Compatibility Test | Өөр орчинд ажиллах эсэх | Машин шороон замд ч зүгээр юу? |
ХЭСЭГ 2: ТҮЛХҮҮР ҮГ БА МЭРГЭЖЛИЙН НЭР ТОМЬЁО (Keywords & Glossary)
| # | Англи нэр томьёо | Монгол утга | Дэлгэрэнгүй тайлбар |
|---|---|---|---|
| 1 | Software Testing | Програм хангамжийн тестчилэл | Програм зөв ажиллаж байгаа эсэхийг шалгах, алдааг олох, чанарыг баталгаажуулах процесс. |
| 2 | Unit Testing | Нэгж тест | Кодын хамгийн жижиг нэгжийг (метод, функц) тусад нь шалгах. Хамгийн хурдан, хамгийн олон тест. |
| 3 | Integration Testing | Нэгтгэлийн тест | Олон модуль нэгдэж зөв ажиллаж байгаа эсэхийг шалгах. |
| 4 | System Testing | Системийн тест | Бүхэл системийг шаардлагын дагуу шалгах. |
| 5 | Acceptance Testing | Хүлээн авах тест | Хэрэглэгч / захиалагч системийг хүлээн авахын өмнө хийх тест. |
| 6 | Regression Testing | Регрессийн тест | Шинэ код хуучин функцийг эвдсэн эсэхийг шалгах. |
| 7 | Smoke Testing | Утааны тест | Системийн суурь функцүүд ажиллаж байна уу гэдгийг хурдан шалгах. |
| 8 | Black-Box Testing | Хар хайрцагны тест | Кодын дотоод бүтцийг мэдэхгүйгээр оролт → гаралтыг шалгах. |
| 9 | White-Box Testing | Цагаан хайрцагны тест | Кодын дотоод бүтцийг мэдэж бүх замналуудыг шалгах. |
| 10 | Grey-Box Testing | Саарал хайрцагны тест | Хар + Цагаан хайрцагны хослол. Дотоод бүтцийн зарим мэдлэгтэй. |
| 11 | TDD (Test-Driven Development) | Тестэнд суурилсан хөгжүүлэлт | Тестээ эхлээд бичиж, дараа нь кодоо бичих арга. Red-Green-Refactor цикл. |
| 12 | BDD (Behavior-Driven Development) | Зан төлөвд суурилсан хөгжүүлэлт | Хэрэглэгчийн зан төлөвөөс эхлэн тест, код бичих. Given-When-Then загвар. |
| 13 | JUnit | Жи-Юнит | Java-ийн хамгийн алдартай unit тестийн фреймворк. |
| 14 | Test Case | Тестийн тохиолдол | Нэг тодорхой нөхцөлд системийн зан төлөвийг шалгах тест. |
| 15 | Test Suite | Тестийн багц | Хэд хэдэн test case-ийг бүлэглэсэн цуглуулга. |
| 16 | Assertion | Баталгаа / Нотолгоо | Тестийн хүлээгдэж буй үр дүнг бодит үр дүнтэй харьцуулах. assertEquals, assertTrue гэх мэт. |
| 17 | Code Coverage | Кодын хамралт | Тестээр кодын хэдэн хувь хамрагдсан бэ гэдгийг хэмждэг. |
| 18 | Statement Coverage | Мэдэгдлийн хамралт | Кодын мөр бүр дор хаяж 1 удаа ажиллаж байгааг шалгах. |
| 19 | Branch Coverage | Салаалтын хамралт | if/else бүр хоёр чиглэлд тестлэгдсэн эсэхийг шалгах. |
| 20 | Mock | Хиймэл объект (Мок) | Бодит объектын оронд ашигладаг хиймэл объект. Зан төлөвийг шалгахад ашигладаг. |
| 21 | Stub | Орлуулагч (Стаб) | Тогтмол хариу буцаадаг хялбар хиймэл объект. |
| 22 | Bug / Defect | Алдаа / Согог | Кодын буруу ажиллагаа. Хүлээгдэж буй үр дүнгээс зөрүү. |
| 23 | Equivalence Partitioning | Эквивалент ангилал | Оролтыг ижил зан төлөвтэй бүлгүүдэд хуваах. Бүлэг бүрээс нэг утга тестлэх. |
| 24 | Boundary Value Analysis | Хил заагийн шинжилгээ | Хилийн утгууд дээр алдаа их гардаг → Хилийн утгуудыг онцгойлон тестлэх. |
| 25 | Decision Table | Шийдвэрийн хүснэгт | Олон нөхцөлийн хослолуудыг хүснэгтээр тестлэх арга. |
| 26 | AAA Pattern | AAA загвар | Arrange (бэлтгэх) → Act (үйлдэл хийх) → Assert (шалгах). Тестийн бүтцийн загвар. |
| 27 | FIRST Principles | FIRST зарчим | Fast, Independent, Repeatable, Self-validating, Timely — Сайн тестийн 5 чанар. |
| 28 | Red-Green-Refactor | Улаан-Ногоон-Дахин засвар | TDD-ийн 3 алхам: Тест fail → Тест pass → Код цэвэрлэх. |
| 29 | Test Fixture | Тестийн тохиргоо | Тест ажиллуулахад шаардлагатай бэлтгэлийн өгөгдөл, объектууд. |
| 30 | @Test | Тест аннотаци | JUnit-д метод нь тест гэдгийг заах аннотаци. |
| 31 | @BeforeEach | Тест бүрийн өмнө | Тест бүрийн өмнө ажиллах setup метод. |
| 32 | @AfterEach | Тест бүрийн дараа | Тест бүрийн дараа ажиллах teardown метод. |
| 33 | @ParameterizedTest | Параметрчилсэн тест | Олон утгаар нэг тестийг давтах. |
| 34 | assertThrows | Exception шалгах | Тодорхой exception үүсгэж байгаа эсэхийг шалгах assert метод. |
| 35 | Performance Testing | Гүйцэтгэлийн тест | Системийн хурд, хариу өгөх хугацааг шалгах. |
| 36 | Load Testing | Ачааллын тест | Олон хэрэглэгчийн ачаалал дор системийн ажиллагааг шалгах. |
| 37 | Stress Testing | Хүчний тест | Системийн хязгаарын ачааллыг шалгах. |
| 38 | Security Testing | Аюулгүй байдлын тест | Системийн аюулгүй байдлыг шалгах. |
| 39 | Test Pyramid | Тестийн пирамид | Unit тест олон, Integration дунд, E2E цөөн байх бүтэц. |
| 40 | Continuous Testing | Тасралтгүй тестчилэл | CI/CD дамжуулгад тест автоматаар ажиллуулах. Код push хийх бүрт тест ажиллана. |