Testing qo'llanmasi — unit, integration, e2e, TDD
Senior dasturchini junior'dan ajratadigan narsalardan biri — test yozish odati. Test — kodga ishonch, refaktoring erkinligi va "tunda qo'ng'iroq" kamayishi. Bu qo'llanma kitobning 11.17 va 15-QISMiga tayanadi.
1. Nega test yozamiz?
- Ishonch — kod ishlashini isbotlaydi (qo'lda har safar tekshirmaysan).
- Refaktoring erkinligi — kodni o'zgartirsang, testlar buzilmasligini ko'rsatadi.
- Hujjat — test kod qanday ishlatilishini ko'rsatadi.
- Regressiyani oldini olish — tuzatilgan bug qayta paydo bo'lmaydi.
- Yaxshiroq dizayn — testlanadigan kod — toza, kam bog'liq kod.
"Test yozishga vaqt yo'q" — aslida test yozmaslik keyinchalik ko'proq vaqt yeydi (qo'lda tekshirish, production bug, qo'rqib refaktoring qilmaslik).
2. Test piramidasi
╱╲ E2E (kam, sekin, qimmat)
╱ ╲ — butun tizimni foydalanuvchidek sinaydi
╱────╲ Integration (o'rtacha)
╱ ╲ — bir necha qism birga ishlashini sinaydi
╱────────╲ Unit (ko'p, tez, arzon)
╱__________╲ — bitta funksiya/komponentni alohida sinaydiQoida: ko'p unit, o'rtacha integration, kam e2e. Pastdagilar tez va arzon — ko'p yoz. Yuqoridagilar sekin va mo'rt — kam, lekin muhim oqimlar uchun.
3. Unit test (birlik testi)
Bitta funksiya/komponentni alohida, boshqalardan ajratib sinaydi.
// sum.js
export function sum(a, b) { return a + b; }
// sum.test.js (Jest / Vitest)
import { sum } from "./sum";
describe("sum", () => {
it("ikki musbat sonni qo'shadi", () => {
expect(sum(2, 3)).toBe(5);
});
it("manfiy son bilan ishlaydi", () => {
expect(sum(-1, 1)).toBe(0);
});
});AAA naqshi — har testni 3 qismga bo'l:
it("savatga mahsulot qo'shadi", () => {
const cart = new Cart(); // Arrange (tayyorla)
cart.add({ id: 1, price: 100 }); // Act (bajar)
expect(cart.total).toBe(100); // Assert (tekshir)
});Nimani unit test qilish kerak: sof mantiq (hisob, validatsiya, transform), chekka holatlar (bo'sh, null, manfiy, juda katta).
4. Mocking (soxtalashtirish)
Tashqi bog'liqlikni (DB, API, vaqt) soxta bilan almashtirish — testni tez va bashoratli qiladi.
// API'ni mock qilish
import { getUser } from "./api";
jest.mock("./api");
it("foydalanuvchi ismini ko'rsatadi", async () => {
getUser.mockResolvedValue({ name: "Ali" }); // soxta javob
const result = await loadUserName(5);
expect(result).toBe("Ali");
expect(getUser).toHaveBeenCalledWith(5); // to'g'ri chaqirilganini tekshir
});Mock turlari: stub (tayyor javob qaytaradi), spy (chaqiruvni kuzatadi), mock (ikkalasi). Vaqt: jest.useFakeTimers() bilan setTimeoutni boshqar.
Hammasini mock qilma. Faqat sekin/tashqi/bashoratsiz narsalarni (tarmoq, DB, vaqt, tasodif). Ortiqcha mock — testni mo'rt qiladi.
5. Integration test
Bir necha qism birga ishlashini sinaydi (masalan API endpoint + DB).
// Express API'ni real (test) DB bilan sinash
import request from "supertest";
import { app } from "./app";
describe("POST /users", () => {
it("yangi foydalanuvchi yaratadi", async () => {
const res = await request(app)
.post("/users")
.send({ name: "Ali", email: "ali@mail.uz" });
expect(res.status).toBe(201);
expect(res.body.id).toBeDefined();
});
it("noto'g'ri email'ni rad etadi", async () => {
const res = await request(app).post("/users").send({ email: "xato" });
expect(res.status).toBe(400);
});
});Test DB: alohida test bazasi (yoki Docker'da vaqtinchalik PostgreSQL — testcontainers). Har testdan keyin tozala.
6. E2E (end-to-end) test
Butun tizimni foydalanuvchidek sinaydi — brauzerni boshqaradi (Playwright/Cypress).
// Playwright
import { test, expect } from "@playwright/test";
test("foydalanuvchi kirib, vazifa qo'shadi", async ({ page }) => {
await page.goto("/login");
await page.fill('[name="email"]', "ali@mail.uz");
await page.fill('[name="password"]', "parol123");
await page.click('button[type="submit"]');
await expect(page).toHaveURL("/dashboard");
await page.fill('[name="task"]', "Test yozish");
await page.click("text=Qo'shish");
await expect(page.locator(".task")).toContainText("Test yozish");
});E2E — eng ishonchli (real foydalanuvchi oqimi), lekin eng sekin/mo'rt. Faqat kritik oqimlar uchun (kirish, to'lov, ro'yxatdan o'tish).
7. TDD (Test-Driven Development)
Avval test, keyin kod. Tsikl: Red Green Refactor.
1. RED — ishlamaydigan test yoz (kod hali yo'q)
2. GREEN — testni o'tkazadigan eng oddiy kodni yoz
3. REFACTOR — kodni tozala (test hali yashil)
takrorlaFoydasi: kod doim testlangan, dizayn yaxshilanadi, ortiqcha kod yozilmaydi. Kamchiligi: o'rganish vaqti, har joyda mos kelmaydi (prototip, UI).
8. Coverage (qamrov)
Kodning necha foizi test bilan qamralganini ko'rsatadi.
jest --coverage # hisobot: % lines, branches, functions100% coverage — maqsad emas. Yuqori foiz testlar yaxshi ekanini bildirmaydi (ma'nosiz test ham foizni oshiradi). Muhim mantiq va chekka holatlar qamralganmi. 70–80% — odatda yaxshi nishon.
9. Yaxshi test belgilari (FIRST)
- Fast — tez (minglab unit test sekundlarda).
- Independent — bir-biriga bog'liq emas (har biri alohida ishlaydi).
- Repeatable — har safar bir xil natija (vaqt/tasodif mock qilingan).
- Self-validating — o'zi pass/fail aytadi (qo'lda tekshirish yo'q).
- Timely — kod bilan birga (yoki oldin) yoziladi.
Yaxshi test: bitta narsani sinaydi, aniq nom ("bo'sh savat 0 qaytaradi"), AAA tuzilishi, mantiq emas — natija sinaydi.
10. Best practices
- Xulqni sina, implementatsiyani emas — ichki tafsilot o'zgarsa test buzilmasin.
- Chekka holatlarni qamrab ol — bo'sh, null, manfiy, juda katta, bir element.
- Aniq test nomi — "nima sinaladi va nima kutiladi".
- Har testdan keyin tozala — DB, mock, holat.
- CI'da test ishlat — har push'da avtomatik (10.5, 15.3).
- Bug topilsa — avval test yoz (regressiyani qaytarmaslik uchun).
- Mock'ni o'lchov bilan ishlat — kam, faqat kerakli joyda.
Mashq
sum,isPalindrome,validateEmailuchun unit testlar yoz (chekka holatlar bilan).- Bir REST endpoint uchun integration test yoz (supertest).
- Kirish oqimi uchun bitta e2e test yoz (Playwright).
- Bir kichik funksiyani TDD bilan yoz (avval test, keyin kod).
Bog'liq: Mashqlar M5/M11 · Bosh sahifa: README.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!