Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. Backend'da to'rt xil test
- 3. Piramida va trofey
- 3.1 Ikki model
- 3.2 Narx va ishonch
- 3.3 Nega backend'da integration ustun
- 4. vazifalar-api ning 67 testi
- 4.1 Integration test qanday ko'rinadi
- 5. Contract testlar
- 5.1 Birinchi ma'no: interfeys shartnomasi
- 5.2 Ikkinchi ma'no: servislar orasidagi shartnoma
- 6. Nimani test qilmaslik
- 7. API qadami: TESTLAR.md (holat 51, 1-qism)
- 8. Ko'p uchraydigan xatolar
- 8.1 Hammasini mock bilan unit qilish
- 8.2 Testlar orasida umumiy holat
- 8.3 E2E bilan hamma narsani tekshirish
- 8.4 listen() ni ilova faylida chaqirish
- 8.5 Raqam uchun test yozish
- 9. Mashqlar
- 1-mashq (oson): darajani aniqlang
- 2-mashq (o'rta): kesh shartnomasi
- 3-mashq (qiyin): yangi endpoint uchun test rejasi
- 4-mashq: API qadami
- 10. Real ishda
- Xulosa
- Manbalar
Backend test strategiyasi: unit, integration, e2e va contract testlar
Qisqacha: Backend'ning asosiy qiymati — HTTP shartnomasi (qaysi so'rovga qaysi status, sarlavha va tana) va ma'lumotning to'g'ri saqlanishi. Shuning uchun backend'da eng foydali test — integration test: haqiqiy HTTP so'rov → haqiqiy Express → xotiradagi ombor. U unit testdan biroz sekin, lekin ichki refaktoringda buzilmaydi va haqiqiy xatolarni ushlaydi. Test "trofeyi" modelida aynan shu qatlam eng keng.
vazifalar-apining 67 testidan 41 tasi HTTP integration, 13 tasi contract (shartnoma) testi — har ombor (xotira, fayl, 26-qismda Postgres) bir xil testdan o'tadi.
Bu darsda
- Backend'dagi unit, integration, e2e va contract testlarni farqlay olasiz.
- Test piramidasi va test trofeyini solishtirib, backend uchun tanlov qilasiz.
- Testning narxi va ishonchliligi orasidagi muvozanatni tushuntirasiz.
- Shartnoma testini yozib, uni ikki xil amalga oshirishda ishlatasiz.
vazifalar-apitestlarini darajalar bo'yicha o'zingiz sanay olasiz.
Oldin bilishingiz kerak: Nega test yozamiz va frontend test turlari, Birinchi avtomatik test: node:test, express.Router va qatlamli tuzilma, Global error handler.
1. Nega bu kerak?
Xato iyerarxiyasi darsida vazifalar-api ning ichi jiddiy o'zgardi: HttpXato o'chdi, olti yangi klass paydo bo'ldi, xizmat va marshrutlar qayta yozildi. Shunga qaramay testlar o'zgarmasdan o'tdi. Nega? Chunki ular ichki klasslarni emas, tashqi xulqni tekshiradi: "bo'sh matn yuborsam — 422 va Problem Details".
Teskari holat ham bo'ldi. Kanon 22-qism frontendini API'ga haqiqiy brauzerda uladi va frontend'da 4 ta o'zgarish kerak bo'ldi: api.ts (manzil, sahifalash, xato formati), .env sozlamasi, Vite proxy va CSP. Ularning hech birini API testlari ushlamadi — muammolar API va frontend orasidagi chegarada edi. Bu ulanishni o'zingiz Coverage darsining «Frontend'ni ulash» bo'limida qilasiz.
Ikkala voqea bitta savolga olib keladi: qaysi testni, qancha va qayerda yozish kerak? Bu — test strategiyasi. Hayotiy o'xshatish: avtomobil zavodidagi sifat nazorati. Har bolt alohida tekshiriladi (unit), lekin eng ko'p vaqt yig'ilgan dvigatelni stendda yurgizishga ketadi (integration). Har mashinani yo'lga olib chiqish (e2e) qimmat — bu faqat bir nechta namuna bilan qilinadi.
2. Backend'da to'rt xil test
FT-01 darsida frontend test turlarini ko'rgansiz. Backend'da ular quyidagicha ko'rinadi:
| Tur | Nimani tekshiradi | vazifalar-api misoli |
|---|---|---|
| Unit | bitta toza funksiya, I/O'siz | kunBoshiUtc("2026-10-24", "Asia/Tashkent") |
| Integration | bir necha qatlam birga, haqiqiy HTTP | POST /v1/vazifalar → 201 + Location |
| E2E | butun tizim: brauzer + frontend + API | Playwright: vazifa qo'shish, sahifani yangilash |
| Contract | ikki tomon orasidagi kelishuv | har ombor bir xil omborShartnomasi() dan o'tadi |
Ta'riflarni aniqlaymiz.
Unit test (unit test) — bitta kichik birlikni (funksiya, klass) tashqi dunyodan ajratib tekshiradi. Tez (millisekundlar), sababini aniq ko'rsatadi, lekin "bo'laklar birga ishlaydimi?" degan savolga javob bermaydi.
Integration test (integration test) — bir necha qismning birga ishlashini tekshiradi. Backend'da odatda: ilovani tasodifiy portda (listen(0)) yoki portsiz ishga tushirish, haqiqiy HTTP so'rov yuborish va javobni tekshirish. Ichida haqiqiy marshrut, middleware, validatsiya, xato ishlovchi va (xotiradagi) ombor ishlaydi.
E2E test (end-to-end) — tizimni foydalanuvchi ko'zi bilan, boshidan oxirigacha: brauzer, frontend, API, baza. Eng ishonchli, eng sekin va eng mo'rt.
Contract test (contract test) — "shartnoma testi": ikki tomon kelishgan qoidani tekshiradi. Uning ikki ma'nosi bor — «Contract testlar» bo'limida.
Tekshirib ko'ring:
test/rest.test.tsdagi "sahifala: kursor qatori o'chirilsa ham keyingisidan davom etadi" testisahifala()funksiyasini to'g'ridan chaqiradi, server ochmaydi. U qaysi tur?
Javob
Unit. Server yo'q, HTTP yo'q, faqat toza funksiya va massiv. Fayl nomi (rest.test.ts) turini belgilamaydi — muhimi test nimani ishga tushiradi. Shu faylning qolgan 6 testi esa integration: ular serverga fetch yuboradi.
3. Piramida va trofey
3.1 Ikki model
Test piramidasi (test pyramid) — eski va mashhur model (Mike Cohn, 2009): pastda ko'p unit, o'rtada kamroq integration, tepada ozgina e2e. G'oyasi: arzon testlar ko'p, qimmatlari kam.
Test trofeyi (testing trophy) — Kent C. Dodds modeli (2018): pastda statik tekshiruv (TypeScript, ESLint), keyin unit, eng keng qatlam — integration, tepada e2e. G'oyasi: "foydalanuvchi qanday ishlatsa, shunday tekshir" — eng ko'p ishonchni integration beradi.
flowchart TB
subgraph T[Trofey: backend]
direction TB
T4[E2E — oz]
T3[Integration — eng ko'p]
T2[Unit — o'rtacha]
T1[Statik: tsc, eslint]
T4 --- T3 --- T2 --- T1
end
subgraph P[Piramida]
direction TB
P3[E2E — oz]
P2[Integration — o'rtacha]
P1[Unit — eng ko'p]
P3 --- P2 --- P1
endRasmga qarang: farq o'rtadagi qatlamda. Piramidada eng ko'p — unit, trofeyda — integration.
3.2 Narx va ishonch
Har test uch narsa bilan o'lchanadi:
| Tur | Tezlik | Ishonch ("ishlab chiqarishda ham ishlaydi") | Refaktoringda buziladimi |
|---|---|---|---|
| Unit | juda tez | past–o'rta | ko'pincha (ichki tuzilmaga bog'liq) |
| Integration | tez–o'rta | yuqori | kam (tashqi xulqqa bog'liq) |
| E2E | sekin | eng yuqori | ba'zan (UI o'zgarsa) |
"Refaktoringda buziladimi" ustuni ko'pincha unutiladi. Ichki funksiyani mock bilan tekshiradigan unit test kodni o'zgartirganda qizil bo'ladi — xulq to'g'ri bo'lsa ham. Bunday test yolg'on qizil (false negative) beradi va jamoa unga ishonmay qo'yadi (FT-01 atamasi).
3.3 Nega backend'da integration ustun
Uch sabab:
- Qiymat chegarada. Mijoz
vazifalar-apidan funksiyalarni emas, HTTP javoblarni oladi: status, sarlavha, Problem Details. Shuni tekshirgan test — eng qimmatli. - Arzon bo'ldi. Express ilovasi xotiradagi ombor bilan bir necha millisekundda ishga tushadi. Kanon o'lchovida 15 fayl, 62 test (
mock.test.tsdan tashqari hammasi)node --testbilan 2.5 soniyada o'tdi (t46-runner.txt). "Integration sekin" degan gap bazali, tarmoqli eski loyihalardan qolgan. - Haqiqiy xatolar chegarada. Kanon topgan xatolarning ko'pi qatlamlar orasida edi: Express 5 da jim
req.body undefined, 416 o'rniga 500,fetch+If-None-Match→ 304 kelmasligi. Bularni hech qanday unit test ushlamasdi.
Unit test qachon kerak? Mantiq murakkab va kirish-chiqish aniq bo'lsa: sana hisoblash (DST), kursor kodlash, Zod sxemalari, sahifalash. Ularda ko'p chegaraviy holat bor — har birini HTTP orqali tekshirish ortiqcha.
4. vazifalar-api ning 67 testi
Kanon testlarini fayllar bo'yicha qayta sanadik (holat 51):
- Unitconfig, sana, sxema, sahifala, teglar, sorovId10 test
- Contract (ombor)5 × 2 ombor + FaylOmbori 313 test
- HTTP integration33 fetch/node:http + 8 supertest41 test
- Jarayonexit 1, graceful shutdown3 test
Manba: IlmHamroh kanon, holat 51 (test/*.test.ts, 2026-10-24) — fayllar bo'yicha qo'lda sanaldi
Trofey shakli aniq ko'rinadi: integration — eng keng qatlam. E2E (frontend + API brauzerda) repo'da test sifatida yo'q — kanon uni bir marta qo'lda, Playwright bilan bajardi.
Diqqat: kanon
TESTLAR.mdjadvalida HTTP integration uchun "46" va supertest uchun "9" yozilgan — bu raqamlar boshqa qatorlar bilan qo'shilganda 67 emas, 81 bo'ladi. Biz hartest(...)chaqiruvini fayl bo'yicha sanadik va 10 + 13 + 41 + 3 = 67 chiqdi (bunpm testdagitests 67bilan mos). Hujjatdagi raqamlar ham kod kabi eskirishi mumkin — ularni ham tekshiring.
4.1 Integration test qanday ko'rinadi
Kanondagi birinchi test (test/api.test.ts, qisqartirilgan):
before(async () => ({ asos, yop } = await ishgaTushir()));
after(() => yop());
test("CRUD: yaratish → o'qish → … → o'chirish", async () => {
const r = await fetch(`${asos}/v1/vazifalar`, jsonYubor("POST", {
matn: "Non olish #uy",
}));
assert.equal(r.status, 201);
assert.equal(r.headers.get("location"), "/v1/vazifalar/1");
// … GET, PATCH, DELETE
});ishgaTushir() — ilovani port 0 da (OS bo'sh portni o'zi beradi) va yangi xotira ombori bilan ishga tushiradi. Har test fayli o'z serveri va omborini oladi — testlar bir-biriga xalaqit bermaydi va parallel ishlay oladi.
Buning uchun arxitektura tayyor bo'lishi kerak edi:
ilova.tsdalisten()yo'q — ilova yasaladi, tinglash alohida (qatlamli tuzilma qarori).- Bog'liqliklar tashqaridan beriladi (
ilovaYarat({ ombor, log, … })) — testda boshqa ombor, jim logger. process.envfaqatserver.tsda o'qiladi — testlar muhitga bog'liq emas.
Bu — sinovga qulay arxitektura (testability). Testni keyin yozish oson bo'lishi uchun uni oldindan loyihalash kerak.
5. Contract testlar
5.1 Birinchi ma'no: interfeys shartnomasi
vazifalar-api da VazifaOmbori interfeysi bor va uning ikki amalga oshirishi: XotiraOmbori va FaylOmbori. 26-qismda uchinchisi — Postgres — qo'shiladi. Ular bir xil xulq ko'rsatishi shart: id 1 dan, ol() nusxa qaytaradi, versiya har yozuvda oshadi.
Har ombor uchun alohida test yozish o'rniga kanon bitta shartnoma funksiyasi yozdi va uni har omborga qo'lladi. G'oyani kichik misolda ko'ramiz — ikki ombor, biri xatoli:
import assert from "node:assert/strict";
// Shartnoma: har "ombor" shu talablarga javob berishi kerak
async function omborShartnomasi(nom, yarat) {
const o = yarat();
const a = await o.qosh("Non olish");
const b = await o.qosh("Sut");
assert.deepEqual([a.id, b.id], [1, 2], "id 1 dan ketma-ket");
const olingan = await o.ol(1);
olingan.matn = "buzildi";
const yana = await o.ol(1);
assert.equal(yana.matn, "Non olish", "ol() nusxa beradi");
assert.equal(await o.ol(99), undefined, "yo'q id — undefined");
console.log(`✔ ${nom}`);
}
class MapOmbori {
#m = new Map();
async qosh(matn) {
const v = { id: this.#m.size + 1, matn };
this.#m.set(v.id, v);
return { ...v };
}
async ol(id) {
const v = this.#m.get(id);
return v && { ...v };
}
}
class MassivOmbori {
#r = [];
async qosh(matn) {
const v = { id: this.#r.length + 1, matn };
this.#r.push(v);
return v;
}
async ol(id) {
return this.#r.find((v) => v.id === id); // nusxa emas!
}
}
const omborlar = [
["Map", () => new MapOmbori()],
["massiv", () => new MassivOmbori()],
];
for (const [nom, yarat] of omborlar) {
try {
await omborShartnomasi(nom, yarat);
} catch (x) {
console.log(`✘ ${nom}: ${x.message.split("\n")[0]}`);
}
}Konsolda:
✔ Map
✘ massiv: ol() nusxa beradiMassivOmbori ichki obyektni to'g'ridan qaytardi — chaqiruvchi uni o'zgartirdi va ombordagi ma'lumot buzildi. Shartnoma buni ushladi. Bu xato 26-qismda muhim: Postgres har safar yangi obyekt qaytaradi, xotiradagi ombor esa qaytarmasligi mumkin edi — testlar xotirada o'tib, prod'da boshqacha ishlardi.
Kanondagi haqiqiy shartnoma (test/ombor-shartnoma.ts) 5 test, ishlatilishi — ikki qator:
omborShartnomasi("xotira", () => Promise.resolve(new XotiraOmbori()));
omborShartnomasi("fayl", async () =>
FaylOmbori.och(join(await yangiPapka(), "ichki", "v.json")));26-qism bitta qator qo'shadi: omborShartnomasi("postgres", …).
5.2 Ikkinchi ma'no: servislar orasidagi shartnoma
Ko'proq tarqalgan ma'nosi — iste'molchi va provayder orasidagi shartnoma. Frontend (iste'molchi) API'dan (provayder) aniq shakl kutadi: vazifalar massivi, xato bo'lsa detail maydoni. API o'zgarsa va frontend bilmasa — ishlab chiqarishda buziladi.
vazifalar-api da bu aynan sodir bo'ldi. Problem Details darsida xato javobi { "xato": "…" } dan Problem Details'ga o'tdi — buzuvchi o'zgarish. API testlari yashil edi (ular yangi formatni kutardi). Frontend esa xato maydonini o'qirdi va buni faqat brauzerdagi ulanish sinovi ko'rsatdi.
Shartnoma testi buni oldindan ushlashi mumkin edi. Ikki mashhur yo'l (kanonda yo'q, hujjat bo'yicha):
| Yo'l | Qanday | Vositalar |
|---|---|---|
| Iste'molchi boshqaradigan (consumer-driven) | frontend testlari "men shuni kutaman" faylini yozadi, API CI'da shu faylga qarshi tekshiriladi | Pact |
| Sxema asosida | API sxemasi (OpenAPI / JSON Schema) yagona manba; ikkala tomon unga qarshi tekshiriladi | Zod toJSONSchema, OpenAPI validatorlar |
Kanonda ikkinchi yo'lning yarmi bor: npm run sxema Zod sxemalaridan docs/sxemalar.json yasaydi (Zod 4 serverda). Uni frontend testlarida ishlatish — shartnomaning ikkinchi yarmi; 25-qismda qilinmagan.
Tekshirib ko'ring: Ombor shartnomasi testi va Pact testi — ikkalasi ham "contract". Asosiy farq nimada?
Javob
Ombor shartnomasi — bitta jarayon ichida, bitta interfeysning bir nechta amalga oshirishi uchun: "hammasi bir xil xulq ko'rsatsin". Pact — ikki alohida dastur (ko'pincha alohida jamoalar) orasida: "provayder iste'molchi kutgan javobni bersin". Birinchisi almashtiriladigan qismlarni, ikkinchisi tarmoq chegarasini himoya qiladi.
6. Nimani test qilmaslik
Strategiya — nimani yozish bilan birga, nimani yozmaslik ham:
- Kutubxonaning ichi. Express marshrutlashni, Zod
min(1)ni to'g'ri ishlashini tekshirish — ularning mualliflari ishi. Siz faqat o'z sozlamangizni tekshirasiz: "bo'sh matn → 422". - Ichki tuzilma. "
xizmat.yaratombor.yaratni chaqirdimi" — faqat bu xulqning o'zi bo'lsa (masalan, idempotentlikda ombor chaqirilmasligi kerak — keyingi darslarda). - Trivial kod. Getter, bir qatorli o'tkazgich.
- Tasodifiy tafsilot. Xato xabarining har so'zi — o'zgaradi; status va
kodmaydoni — barqaror.
7. API qadami: TESTLAR.md (holat 51, 1-qism)
Holat 51 — vazifalar-api v1 ning yakuni — yetti darsga bo'lingan: bugungi strategiya, node:test, test dublyorlari, Supertest, tashqi HTTP, vaqt va tasodif, coverage. Hali commit qilmang — commit yettinchi darsda. Har dars oxirida npm run check yashil bo'lib turadi: bugun kod o'zgarmaydi, testlar holat 44 dagidek 58 ta.
Bugun — hujjat: loyiha ildizida TESTLAR.md. Kanondagi qoidalar qismi:
## Qoidalar
- Har test o'z serveri/omborini yaratadi — testlar orasida holat yo'q
(port 0 — parallel ishlaydi).
- Vaqt va tasodif: XotiraOmbori(soat), sorovId(yangiId) — ukol;
yoki t.mock.timers.enable({ apis: ["Date"] }).
- Tashqi HTTP: webhookXabarchi(url, { fetchFn }) — soxta fetch.
Tarmoqqa chiqadigan test yo'q.
- Shartli so'rovlar (If-None-Match) — fetch bilan EMAS: undici o'zi
Cache-Control: no-cache qo'shadi.
- Coverage foizi — sifat emas: test chaqirmagan fayl (server.ts)
hisobotda umuman YO'Q.(Qatorlar telefon uchun bo'lindi.) Bu qoidalarning har biri keyingi darslarda alohida mavzu. Jadvalni esa o'zingiz yozasiz — 4-mashqda, o'z sanog'ingiz bilan.
8. Ko'p uchraydigan xatolar
8.1 Hammasini mock bilan unit qilish
Har qatlam soxta bog'liqliklar bilan tekshirilgan, lekin ular birga hech qachon ishga tushmagan. Testlar yashil, ilova ishlamaydi. Asosiy oqimlar — haqiqiy HTTP orqali.
8.2 Testlar orasida umumiy holat
Bitta global ombor: birinchi test vazifa qo'shdi, ikkinchisi "ro'yxat bo'sh" deb kutdi. Natija tartibga bog'liq — yakka ishga tushirsangiz o'tadi, hammasi bilan — yiqiladi. Har test (yoki fayl) yangi ombor.
8.3 E2E bilan hamma narsani tekshirish
Sekin (soniyalar), mo'rt (UI matni o'zgarsa), sababini topish qiyin. E2E — faqat eng muhim foydalanuvchi yo'llari uchun.
8.4 listen() ni ilova faylida chaqirish
Test ilovani import qilganda server port band qiladi va jarayon tugamaydi — node --test osilib qoladi (Supertest darsida haqiqiy chiqish bilan ko'ramiz). ilova.ts — yasaydi, server.ts — tinglaydi.
8.5 Raqam uchun test yozish
"Coverage 100 % bo'lsin" deb trivial kodga test. Xavf qayerda — test shu yerda (Coverage darsi).
9. Mashqlar
1-mashq (oson): darajani aniqlang
Kanon testlari quyida. Har biri qaysi daraja?
- (a) "config: noto'g'ri qiymat — ConfigXatosi, hammasi bitta xabarda"
- (b) "PUT /v1/vazifalar — butun to'plam: id saqlanadi…"
- (c) "VazifaOmbori shartnomasi: fayl — yangila…"
- (d) "unhandledRejection: log → boshlangan so'rov tugaydi → exit 1"
- (e) "supertest: shartli so'rov — 304"
Yechim
(a) Unit — configYukla(obyekt) toza funksiya. (b) HTTP integration — fetch bilan PUT. (c) Contract — shartnoma funksiyasi fayl omboriga qo'llangan. (d) Jarayon — alohida bola jarayon ishga tushiriladi va uning exit kodi tekshiriladi. (e) HTTP integration (portsiz, supertest bilan). Bu taqsimot «67 testi» bo'limidagi grafik bilan mos.
2-mashq (o'rta): kesh shartnomasi
Kesh interfeysi: ol(kalit) — qiymat yoki undefined; qoy(kalit, qiymat); ochir(kalit) — o'chirildimi (true/false). keshShartnomasi(nom, yarat) yozing (kamida 3 talab) va ikki amalga oshirishga qo'llang: Map asosidagi va oddiy obyekt ({}) asosidagi. Ikkinchisida ochir doim true qaytarsin — shartnoma buni ushlasin. Eslatma: node:assert/strict — node:test darsidan.
Yechim
import assert from "node:assert/strict";
function keshShartnomasi(nom, yarat) {
const k = yarat();
assert.equal(k.ol("a"), undefined, "bo'sh kesh");
k.qoy("a", 1);
assert.equal(k.ol("a"), 1, "qo'yilgan qiymat");
assert.equal(k.ochir("a"), true, "bor kalit o'chadi");
assert.equal(k.ochir("a"), false, "yo'q kalit — false");
console.log(`✔ ${nom}`);
}
const mapKesh = () => {
const m = new Map();
return {
ol: (k) => m.get(k),
qoy: (k, v) => m.set(k, v),
ochir: (k) => m.delete(k),
};
};
const obyektKesh = () => {
const o = {};
return {
ol: (k) => o[k],
qoy: (k, v) => { o[k] = v; },
ochir: (k) => delete o[k], // delete doim true qaytaradi
};
};
const keshlar = [["Map", mapKesh], ["obyekt", obyektKesh]];
for (const [nom, yarat] of keshlar) {
try {
keshShartnomasi(nom, yarat);
} catch (x) {
console.log(`✘ ${nom}: ${x.message.split("\n")[0]}`);
}
}Konsolda:
✔ Map
✘ obyekt: yo'q kalit — falsedelete operatori kalit bo'lmasa ham true qaytaradi — bu JavaScript'ning eski xususiyati. Shartnoma uni ushladi. Obyekt kalitida yana bitta tuzoq bor: ol("toString") — undefined emas, funksiya. Uni shartnomaga 5-talab qilib qo'shib ko'ring.
3-mashq (qiyin): yangi endpoint uchun test rejasi
vazifalar-api ga POST /v1/vazifalar/:id/nusxa qo'shilmoqda: vazifaning nusxasini yaratadi (matn va teglar bir xil, bajarildi: false, yangi id), 201 + Location; yo'q id — 404 Problem Details; ro'yxat to'lgan bo'lsa — 409. Qaysi testlarni, qaysi darajada yozasiz? Kod yozmang — reja bering.
Yechim
Namuna reja:
- Integration (asosiy, 3–4 ta). (1) Mavjud vazifa → 201,
Locationyangi id'ga, GET bilan matn va teglar bir xil,bajarildi: false. (2) Yo'q id → 404,content-type: application/problem+json,kod. (3) Noto'g'ri id (abc) → 400. (4) Ro'yxat to'lgan → 409;MAKS_VAZIFAni o'zgartirib bo'lmasa, omborni oldindan to'ldiring. - Contract: agar
VazifaOmboriga yangi metod (nusxa) qo'shilsa — shartnomaga test, aks holda kerak emas (xizmatol+yaratbilan qila oladi). - Unit: kerak emas — mantiq oddiy; HTTP testlari uni to'liq qamraydi.
- E2E: faqat frontend'da "nusxa" tugmasi bo'lsa.
- Idempotentlik: endpoint
POST—Idempotency-Keybilan takrorda ikkinchi nusxa yaratilmasligini tekshirish (Idempotency-Key).
Asosiy fikr: test soni endpoint'ning xulq holatlari soniga teng, kod qatorlari soniga emas.
4-mashq: API qadami
vazifalar-api ildizida TESTLAR.md yarating: strategiya (bir gap), «67 testi» bo'limidagi kabi jadval — lekin o'z loyihangiz testlarini fayl bo'yicha sanab, va «API qadami» bo'limidagi qoidalar. Jadvaldagi raqamlar yig'indisi npm test dagi tests bilan teng bo'lsin. Commit qilmang.
Yechim
Sanash uchun: har *.test.ts faylda test( chaqiruvlarini sanang (grep -c "^test(" test/*.test.ts), shartnoma funksiyasi ichidagilarni ombor soniga ko'paytiring. Keyin har testni bir qatorda o'qib, darajasini belgilang: server ochiladimi (integration), bola jarayonmi (jarayon), faqat funksiyami (unit). Kanon holati 51 da: 10 + 13 + 41 + 3 = 67. Yig'indi npm test bilan mos kelmasa — qaysidir faylni ikki marta sanagansiz yoki describe ichidagini unutgansiz.
10. Real ishda
- Katta kompaniyalar backend'da integration testni "service test" yoki "component test" deb ataydi — ma'nosi bir xil: servis o'zi butun, tashqi bog'liqliklari soxta yoki konteynerda.
- Baza bilan integration: 26–27-qismlarda xotiradagi ombor o'rniga haqiqiy Postgres (Testcontainers yoki alohida test bazasi) bilan ham testlar bo'ladi — shartnoma testlari aynan shu ko'prik.
- Pact mikroservisli kompaniyalarda keng tarqalgan; frontend va backend jamoalari alohida bo'lsa — ayniqsa foydali.
- Intervyu savollari: "Test piramidasi va trofeyi farqi?", "Backend'da qaysi testlarni ko'proq yozasiz va nega?", "Contract test nima?", "Testga qulay arxitektura qanday bo'ladi?".
Xulosa
- Backend'da to'rt tur: unit (toza funksiya), integration (haqiqiy HTTP + qatlamlar), e2e (butun tizim), contract (kelishuv).
- Trofey modeli: eng keng qatlam — integration; backend'da u arzon (port 0, xotiradagi ombor) va refaktoringga chidamli.
- Unit — murakkab toza mantiq uchun: sana, kursor, sxema, sahifalash.
- Contract: (1) interfeysning har amalga oshirishi bir xil testdan o'tadi (
omborShartnomasi); (2) servislar orasida — Pact yoki sxema. vazifalar-api: 67 test = 10 unit + 13 contract + 41 integration + 3 jarayon; hujjatdagi raqamlarni ham tekshiring.- Sinovga qulay arxitektura:
listen()siz ilova, tashqaridan beriladigan bog'liqliklar,process.envfaqat kirish nuqtasida.
Keyingi dars: node:test va node:assert — Node'ning o'rnatilgan test runner'i chuqur: describe/it, hook'lar, t.mock, snapshot, --watch va nega kanon Vitest'ni emas, node --test ni tanladi (o'lchov bilan).
Manbalar
- Kent C. Dodds: The Testing Trophy and Testing Classifications (2021).
- Ham Vocke: The Practical Test Pyramid (martinfowler.com, 2018-02-26) — piramida va contract testlar.
- Pact: Introduction — iste'molchi boshqaradigan contract testlar.
- Kanon:
vazifalar-apiholat 51 (TESTLAR.md,test/ombor-shartnoma.ts,test/api.test.ts), frontend ulanish sinovi,t46-runner.txto'lchovi.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!