Mundarija (33)
- Bu darsda
- 1. Nega bu kerak?
- 2. Qamrovning uch turi
- 2.1 Birinchi hisobot
- 2.2 Ustunlarni o'qiymiz
- 3. Chegaralar: CI'da qamrov tushmasin
- 3.1 Node bayroqlari
- 3.2 Kanon: npm run test:qamrov
- 4. vazifalar-api hisoboti
- 4.1 Natija
- 4.2 Halol: foiz nimani yashiradi
- 5. V8 va Istanbul, c8
- 5.1 Ikki usul
- 5.2 c8
- 6. Coverage — sifat emas: mutation testing
- 6.1 Zaif test, 100 % qamrov
- 6.2 Stryker
- 7. API qadami: vazifalar-api 1.0.0 (holat 51, yakun)
- 7.1 Frontend'ni ulash
- 8. Ko'p uchraydigan xatolar
- 8.1 Foizni maqsad qilish
- 8.2 Faqat satr qamroviga qarash
- 8.3 Hisobotda yo'q fayllarni unutish
- 8.4 V8 va Istanbul raqamlarini solishtirish
- 8.5 Chegara tebranishga yaqin
- 9. Mashqlar
- 1-mashq (oson): hisobotni o'qing
- 2-mashq (o'rta): tarmoqni yopish
- 3-mashq (qiyin): o'z mutatoringiz
- 4-mashq: API qadami — v1.0.0
- 10. Real ishda
- Xulosa
- Manbalar
Test coverage va sifat metrikalari: node:test qamrovi, c8 va mutation testing
Qisqacha: Coverage (qamrov) — testlar ishga tushirgan kod ulushi: satr, tarmoq (
if/?:ning har yo'li) va funksiya bo'yicha. Node 24 da kutubxonasiz:node --test --experimental-test-coverage, chegaralar--test-coverage-lines=95kabi — yetmasa exit 1.vazifalar-api1.0.0: satr 97.98 %, tarmoq 89.64 %, funksiya 93.12 %. Lekin bu raqam "hammasi tekshirilgan" degani emas:server.tshisobotda umuman yo'q (testlar uni yuklamaydi), va 100 % qamrovli test ham xatoni o'tkazib yuborishi mumkin — buni mutation testing ko'rsatadi. Coverage faqat tekshirilmagan joyni ko'rsatadi.
Bu darsda
- Satr, tarmoq va funksiya qamrovini farqlay olasiz va hisobotni o'qiysiz.
node --testbilan qamrov o'lchab, chegaralar qo'yasiz.- V8 va Istanbul qamrovi farqini bilasiz va c8 bilan ishlaysiz.
- Yuqori foiz qanday aldashi mumkinligini ikki misolda ko'rsatasiz.
- Mutation testing g'oyasini tushunib, kichik namunasini yozasiz.
- 22-qism
vazifalarfrontend'ini o'zvazifalar-apiingizga ulaysiz.
Oldin bilishingiz kerak: Vitest II: mock, spy, taymerlar va coverage, node:test va node:assert, Backend test strategiyasi, Vaqt va tasodifni boshqarish.
1. Nega bu kerak?
vazifalar-api da 67 test bor. Ular kodning qaysi qismini tekshiradi? Qaysi if ning else qismi hech qachon ishga tushmagan? Buni qo'lda topish — har faylni test bilan solishtirib o'qish. Coverage vositasi buni bir buyruqda qiladi.
Lekin ehtiyot bo'lish kerak. Jamoalarda tez-tez shunday bo'ladi: rahbar "coverage 90 % bo'lsin" deydi, dasturchilar raqamni ko'tarish uchun hech narsani tekshirmaydigan testlar yozadi. Raqam o'sdi, sifat — yo'q.
Hayotiy o'xshatish: bino xavfsizlik xizmatining aylanish jurnali. Qorovul har xonaga kirganini belgilaydi — 98 % xonaga kirilgan. Bu foydali: qolgan 2 % xonaga hech kim kirmagani aniq. Lekin "kirdi" — "diqqat bilan tekshirdi" degani emas. Coverage ham "kod ishladi" deydi, "to'g'ri ishlashi tekshirildi" demaydi.
2. Qamrovning uch turi
2.1 Birinchi hisobot
Kichik misol: chegirma va yetkazish funksiyalari, bitta test.
// chegirma.mjs
export function chegirma(narx, foiz) {
if (foiz < 0 || foiz > 100) {
throw new RangeError("foiz 0..100");
}
const natija = narx * (100 - foiz) / 100;
return foiz > 0 ? Math.round(natija) : narx;
}
export function yetkazish(summa) {
return summa >= 200_000 ? 0 : 15_000;
}// chegirma.test.mjs
import { test } from "node:test";
import assert from "node:assert/strict";
import { chegirma } from "./chegirma.mjs";
test("10 foiz chegirma", () => {
assert.equal(chegirma(35_000, 10), 31_500);
});Biz ishga tushirdik — node --test --experimental-test-coverage (Node 24.21.0; test qatorlari olib tashlandi):
ℹ start of coverage report
ℹ -------------------------------------------------------------
ℹ file | line % | branch % | funcs % | uncovered lines
ℹ -------------------------------------------------------------
ℹ chegirma.mjs | 63.64 | 50.00 | 50.00 | 3-4 10-11
ℹ -------------------------------------------------------------
ℹ all files | 63.64 | 50.00 | 50.00 |
ℹ -------------------------------------------------------------
ℹ end of coverage reportTest fayli hisobotda yo'q — Node test fayllarini sukut bo'yicha chiqarib tashlaydi.
2.2 Ustunlarni o'qiymiz
| Ustun | Ma'nosi | Bizda |
|---|---|---|
| line % | ishga tushgan satrlar ulushi | 11 tadan 7 tasi — 63.64 % |
| branch % | tarmoqlarning qanchasi yurgan | 50 % |
| funcs % | chaqirilgan funksiyalar | 2 tadan 1 tasi — yetkazish hech qachon |
| uncovered lines | yurmagan satrlar | 3–4 (throw), 10–11 (yetkazish) |
Satr qamrovi (line coverage) — eng oddiy: satr bir marta bo'lsa ham bajarildimi.
Tarmoq qamrovi (branch coverage) — har shartning har yo'li. if ning ikki yo'li bor (rost va yolg'on), ?: ning ham. 6-qatorga qarang: foiz > 0 ? Math.round(natija) : narx. Satr qamrovi uchun u "yurdi". Lekin : narx yo'li (0 foiz) hech qachon bajarilmagan — buni faqat tarmoq qamrovi ko'radi.
Funksiya qamrovi (function coverage) — har funksiya kamida bir marta chaqirildimi.
Qaysi biri muhimroq? Tarmoq. Xatolar ko'pincha "kamdan-kam yo'l"da yashaydi: 0 foiz, bo'sh ro'yxat, muddati o'tgan kalit. 100 % satr va 50 % tarmoq — tez-tez uchraydigan holat.
Tekshirib ko'ring: Qaysi bitta testni qo'shsangiz, tarmoq qamrovi oshadi, satr qamrovi esa o'zgarmaydi?
Javob
assert.equal(chegirma(35_000, 0), 35_000) — 0 foiz. U 6-qatordagi : narx yo'lini yuritadi: tarmoq oshadi, lekin yangi satr qo'shilmaydi (6-qator allaqachon yurgan). Satr qamrovini oshirish uchun esa throw (chegirma(1, 101)) va yetkazish testlari kerak.
3. Chegaralar: CI'da qamrov tushmasin
3.1 Node bayroqlari
node --test --experimental-test-coverage \
--test-coverage-lines=90 \
--test-coverage-branches=80 \
--test-coverage-functions=90 \
--test-coverage-include="src/**/*.ts"Chegaraga yetmasa — hisobot oxirida xato va exit 1. Biz kichik misolda --test-coverage-lines=90 bilan sinadik:
ℹ Error: 63.64% line coverage does not meet threshold of 90%.--test-coverage-include va --test-coverage-exclude — qaysi fayllar hisoblanadi. Ishonchli bayroq nomi uchun node --help ga qarang: --experimental-test-coverage Node 24 da hali "experimental" deb belgilangan — bayroq nomi kelajakda o'zgarishi mumkin.
3.2 Kanon: npm run test:qamrov
{
"scripts": {
"test:qamrov": "node --test --experimental-test-coverage --test-coverage-include=\"src/**/*.ts\" --test-coverage-lines=95 --test-coverage-branches=85 --test-coverage-functions=90 \"test/**/*.test.ts\""
}
}Chegaralar: satr 95, tarmoq 85, funksiya 90. Nega 100 emas? Ba'zi kodni test qilish narxi foydasidan katta: masalan jarayon.ts dagi signal ishlovchilari (SIGTERM Windows'da haqiqiy emas — kanon sinamagan). Chegara — "pastga tushmasin" degan himoya, "maqsad" emas.
Kanon chegarani ataylab 99 ga ko'tarib sinadi (t51-qamrov.txt):
--- --test-coverage-lines=99 bilan:
ℹ Error: 97.98% line coverage does not meet threshold of 99%.
[exit 1]4. vazifalar-api hisoboti
4.1 Natija
Kanon to'liq hisobotidan (t51-qamrov.txt) — eng past tarmoq qamrovli fayllar:
- sana.ts50 %
- jarayon.ts62,5 %
- webhook.ts71,43 %
- eksport.ts75,76 %
- log.ts79,17 %
- hammasi89,64 %
Manba: IlmHamroh kanon o'lchovi, 2026-10-24: Node 24.21.0, holat 51 (t51-qamrov.txt)
Jami: satr 97.98 %, tarmoq 89.64 %, funksiya 93.12 %. Hisobotdan parcha:
ℹ file | line % | branch % | funcs % | uncovered lines
ℹ ilova.ts | 100.00 | 100.00 | 100.00 |
ℹ ishga-tushir.ts | 85.11 | 100.00 | 75.00 | 16-22
ℹ jarayon.ts | 100.00 | 62.50 | 50.00 |
ℹ sana.ts | 100.00 | 50.00 | 100.00 |
ℹ webhook.ts | 96.30 | 71.43 | 100.00 | 19
ℹ xato-ishlovchi.ts | 89.80 | 93.33 | 80.00 | 29-33
ℹ all files | 97.98 | 89.64 | 93.12 |Qiziq qator — sana.ts: satr 100 %, tarmoq 50 %. Har satr yurgan, lekin shartlarning yarim yo'li — yo'q. Bu yerda ehtimol DST va noto'g'ri sana yo'llari. Eng xavfli kombinatsiya: vaqt hisoblash + past tarmoq qamrovi.
4.2 Halol: foiz nimani yashiradi
Uchta narsa hisobotda ko'rinmaydi:
server.tsumuman yo'q. Coverage faqat test yuklagan fayllarni hisoblaydi. Hech bir testserver.tsni import qilmaydi (u kirish nuqtasi). Shuning uchun u "0 %" bo'lib emas, umuman yo'q bo'lib qoldi — umumiy foiz shishgan.- Bola jarayondagi kod.
jarayon.test.tsilovani alohida jarayonda yurgizadi (exit 1 ni tekshirish uchun). U jarayonda bajarilgan kod hisobotga kirmaydi —jarayon.tsshuning uchun 62.5 %. - Foiz yurishdan yurishga ozgina farq qildi: bir yurishda tarmoq 89.64 %, boshqasida 89.47 % (
QADAMLAR.md). Sabab aniqlanmagan — ehtimol asinxron yo'llar (fon ishi, webhook) har safar bir xil tartibda yurmaydi. Chegara 85 % — bu tebranishdan ancha past.
Xulosa: 97.98 % — "2 % kod tekshirilmagan" emas. "Yuklangan fayllarning 2 % satri hech qachon ishlamagan, qolgani haqida — noma'lum".
5. V8 va Istanbul, c8
5.1 Ikki usul
Qamrovni ikki yo'l bilan hisoblash mumkin:
| Usul | Qanday | Vositalar |
|---|---|---|
| V8 | JS dvigatelining o'zi qaysi bloklar bajarilganini sanaydi | node --test --experimental-test-coverage, c8, Vitest (sukut) |
| Istanbul | kod oldindan "asboblanadi": har satr va shartga hisoblagich qo'shiladi | nyc, Jest (sukut), Vitest (provider: "istanbul") |
V8 tezroq (kodni o'zgartirmaydi), source map orqali TypeScript qatorlariga qaytaradi. Istanbul aniqroq hisoblaydi (masalan mantiqiy ifoda ichidagi har qism), lekin sekinroq va kodni o'zgartiradi. Ikkalasi bir kodga biroz boshqa raqam berishi mumkin — ularni o'zaro solishtirmang.
5.2 c8
c8 — V8 qamrovini Istanbul formatidagi hisobotlarga (matn, HTML, lcov) aylantiradigan vosita. U istalgan Node buyrug'ini o'raydi. Biz o'sha misolda sinadik (c8 12.0.0, alohida papkada):
npx c8 --reporter=text node --test--------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------|---------|----------|---------|---------|-------------------
All files | 63.63 | 50 | 50 | 63.63 |
chegirma.mjs | 63.63 | 50 | 50 | 63.63 | 3-4,10-11
--------------|---------|----------|---------|---------|-------------------Raqamlar Node'ning o'zinikiga juda yaqin: 63.63 va 63.64 — faqat yaxlitlash farqi (c8 kesadi, Node yaxlitlaydi). Qo'shimcha ustun — % Stmts (ifoda qamrovi). Chegara ham bor:
npx c8 --check-coverage --lines 90 node --testERROR: Coverage for lines (63.63%) does not meet global threshold (90%)Exit kodi — 1 (biz tekshirdik). npx c8 report --reporter=html — coverage/index.html: har fayl rangli, yurmagan satrlar qizil. Kod sharhida juda qulay.
Kanon c8 ni qo'shmadi — Node'ning o'z hisoboti va chegaralari yetarli. c8 HTML yoki lcov (CI xizmatlari uchun) kerak bo'lganda foydali.
6. Coverage — sifat emas: mutation testing
6.1 Zaif test, 100 % qamrov
yetkazish funksiyasi uchun ikki test to'plami. Ikkalasi ham ikki tarmoqni yuritadi — 100 % satr va tarmoq. Qaysi biri yaxshiroq? Buni bilish uchun kodga ataylab kichik xato kiritamiz — mutant. Yaxshi test mutantni "o'ldiradi" (yiqiladi). Mutant "tirik qolsa" — test uni sezmadi.
// Asl kod: 200 000 so'mdan boshlab yetkazish bepul
const asl = (summa) => (summa >= 200_000 ? 0 : 15_000);
// Mutantlar — kodga ataylab kiritilgan kichik xatolar
const mutantlar = {
">= → >": (s) => (s > 200_000 ? 0 : 15_000),
"0 → 1": (s) => (s >= 200_000 ? 1 : 15_000),
"15000 → 0": (s) => (s >= 200_000 ? 0 : 0),
};
// Ikki test to'plami: zaif va kuchli
const zaif = (f) => f(500_000) === 0 && f(50_000) > 0;
const kuchli = (f) =>
f(200_000) === 0 && f(199_999) === 15_000 && f(500_000) === 0;
for (const [nom, tekshir] of [["zaif", zaif], ["kuchli", kuchli]]) {
const tirik = Object.entries(mutantlar)
.filter(([, m]) => tekshir(m))
.map(([n]) => n);
const royxat = tirik.join("; ") || "yo'q";
console.log(`${nom}: asl ${tekshir(asl)}, tirik: ${royxat}`);
}Konsolda:
zaif: asl true, tirik: >= → >
kuchli: asl true, tirik: yo'qZaif to'plam qamrovi 100 %, lekin >= ni > ga almashtirish (aynan 200 000 so'mlik xarid uchun pul olish) sezilmadi. Sabab — chegara qiymati (200 000) tekshirilmagan. Kuchli to'plam chegarani va undan bir so'm kamni tekshiradi — hamma mutant o'ldi.
6.2 Stryker
Qo'lda mutant yozish — faqat g'oyani ko'rsatish uchun. Haqiqiy loyihada buni Stryker (@stryker-mutator/core) avtomatik qiladi: kodda yuzlab mutant yasaydi (>= → >, + → -, true → false, satrni bo'shatish), har biri uchun testlarni yuritadi va mutation score — o'ldirilgan mutantlar ulushini beradi.
Narxi — vaqt: har mutant uchun test to'plami qayta yuradi. Shuning uchun u har commit'da emas, vaqti-vaqti bilan yoki faqat muhim modullarda (to'lov, vaqt hisoblash) ishlatiladi. Kanon Stryker'ni o'rnatmadi — bu yerda faqat tanishuv.
flowchart LR
K[Kod] --> M[Mutant: >= → >]
M --> T{Testlar}
T -->|yiqildi| O[O'ldi — test kuchli]
T -->|o'tdi| Q[Tirik — test zaif]Diagrammaga qarang: mutation testing testlarni tekshiradi, kodni emas.
7. API qadami: vazifalar-api 1.0.0 (holat 51, yakun)
Holat 51 — 25-qismning oxirgi holati. Bugungi o'zgarishlar:
| Fayl | O'zgarish |
|---|---|
package.json |
test:qamrov skripti; "version": "1.0.0" (0.9.0 edi) |
TESTLAR.md |
Backend test strategiyasi darsida yozilgan + coverage qoidasi |
README.md |
yangi: ishga tushirish, skriptlar, endpointlar, config |
docs/sxemalar.json |
npm run sxema — tartib, matn ≤ 100 bilan yangilandi |
Yakuniy tekshiruv (tekshiruv-51.txt):
--- npm run tip
exit 0 (3605 ms)
--- npm run lint
exit 0 (6882 ms)
--- npm run test
ℹ tests 67
ℹ pass 67
ℹ fail 0
--- bog'liqliklar: prod 6 (cors@2.8.6 express@5.3.0 helmet@8.3.0 pino@10.4.0 pino-http@11.0.0 zod@4.6.7), dev 10
--- sovuq start: src/server.ts — n=10, mediana 446.8 ms
--- npm run test:qamrov (xulosa)
ℹ all files | 97.98 | 89.64 | 93.12 |npm run check (tip + lint + test) o'tgach — commit (kanon xabari, holat 51):
git add -A
git commit -m "Testlar: supertest, test double'lar, mock.timers, webhook (tashqi HTTP) va uning soxtasi, coverage chegaralari; TESTLAR.md, README, v1.0.0"
git tag v1.0.0git tag — kanon xabarida yo'q, bizning taklif: 1.0.0 — birinchi barqaror versiya, teg bilan belgilash qulay.
vazifalar-api v1 tayyor: Express 5, REST, Problem Details, idempotentlik, kesh, Zod validatsiya, tipli config, JSON loglar va correlation ID, 67 test. Prod bog'liqliklar — 6 ta. 26-qismda saqlash Postgres'ga o'tadi — VazifaOmbori interfeysi va shartnoma testlari tayyor turibdi.
7.1 Frontend'ni ulash
API tayyor — endi uni haqiqiy mijozga ulaymiz. 22-qismdagi vazifalar frontend'i hozirgacha mashq API'si bilan ishlardi. Kanon frontend nusxasini vazifalar-api ga ulab, haqiqiy brauzerda (Playwright, headless Chromium) sinadi. Frontend'da 4 ta o'zgarish kerak bo'ldi — har biri brauzerda topilgan muammo:
| # | Fayl | O'zgarish | Nega |
|---|---|---|---|
| 1 | src/api.ts |
manzil ${asosiyUrl}/vazifalar; ro'yxat ?limit=100; xato matni detail dan |
foydalanuvchi kaliti yo'q (auth — 28-qism); API sahifalaydi, sukut 20 ta; xato endi Problem Details |
| 2 | .env.development.local |
VITE_API_URL=/v1, API_PROXY=http://127.0.0.1:4150 |
dev'da so'rovlar Vite orqali API'ga boradi |
| 3 | vite.config.ts |
proxy'ga "/v1" qo'shildi |
proxy faqat /api ni uzatardi — /v1 so'rovlari 404 oldi |
| 4 | index.html |
CSP connect-src ga API manzili |
production build boshqa origin'dagi API'ga ulana olmadi |
GET /v1/vazifalar javobi endi { versiya, vazifalar, sahifa } (Pagination darsidagi buzuvchi o'zgarish). Frontend'ning Zod sxemasi versiya va vazifalar ni o'qiydi, noma'lum sahifa ni esa tashlab yuboradi. Shuning uchun shakl o'zgarishi frontend'ni buzmadi. Muammo boshqa joyda edi: sukut bo'yicha faqat 20 ta vazifa kelardi — ?limit=100 shuni hal qiladi.
api.ts dagi xato o'qish (kanon diff'idan):
// 25-qism: vazifalar-api xatoni Problem Details (RFC 9457)
// bilan yuboradi — odam o'qiydigan matn "detail" da;
// eski mashq API'si — { xato: "..." }
function serverXabari(malumot: unknown): string | undefined {
if (typeof malumot !== "object" || malumot === null) {
return undefined;
}
if ("detail" in malumot && typeof malumot.detail === "string") {
return malumot.detail;
}
if ("xato" in malumot && typeof malumot.xato === "string") {
return malumot.xato;
}
return undefined;
}vite.config.ts dagi proxy:
proxy: env.API_PROXY
? {
"/api": { target: env.API_PROXY, changeOrigin: true },
// 25-qism: o'z backend'imiz /v1 da (vazifalar-api)
"/v1": { target: env.API_PROXY, changeOrigin: true },
}
: undefined,Kanon API'ni PORT=4150 da ochgan. Siz o'z portingizni qo'ying — .env.development.local da ham, CSP da ham.
flowchart LR
B[Brauzer] -->|/v1/vazifalar| V[Vite dev server]
V -->|proxy: API_PROXY| A[vazifalar-api :4150]
P[Production build] -->|cross-origin, CORS| ADiagrammaga qarang: dev'da brauzer faqat Vite bilan gaplashadi (bitta origin, CORS kerak emas). Production build'da esa frontend va API alohida origin'da — bu yerda CORS va CSP ishlaydi.
Kanon natijasi (t-frontend.txt, Chromium 151, uch holat):
| Holat | Nima qilindi | Natija |
|---|---|---|
| A — dev, proxy orqali | vazifa qo'shish, belgilash, sahifani yangilash | API'da 5 vazifa, belgilangan holat saqlandi, konsol xatosi yo'q |
| B — production build, boshqa origin | CORS_ORIGINS=http://127.0.0.1:4152 |
GET 200, POST 201, javobda Access-Control-Allow-Origin |
| C — ruxsatsiz origin (4153) | xuddi shu so'rovlar | brauzer bloklaydi: "has been blocked by CORS policy"; ekranda frontend xabari |
B holatida bitta savolga ham javob topildi: helmet qo'yadigan Cross-Origin-Resource-Policy: same-origin CORS rejimidagi fetch ni bloklamadi.
Frontend — alohida repo. O'zgarishlarni o'sha yerda, o'z commit'i bilan saqlang (xabarni o'zingiz yozing, masalan "vazifalar-api ga ulanish: /v1, limit, Problem Details, proxy, CSP"). .env.development.local git'ga kirmaydi — u lokal sozlama.
8. Ko'p uchraydigan xatolar
8.1 Foizni maqsad qilish
"90 % bo'lsin" — natijada assert siz testlar: kod yuradi, hech narsa tekshirilmaydi, qamrov o'sadi. Foiz — pastga tushmaslik chegarasi; maqsad — xavfli joylarda kuchli testlar.
8.2 Faqat satr qamroviga qarash
100 % satr, 50 % tarmoq (sana.ts). Tarmoq ustuni birinchi.
8.3 Hisobotda yo'q fayllarni unutish
server.ts "0 %" emas, umuman yo'q. --test-coverage-include="src/**/*.ts" faqat yuklanganlarni ko'rsatadi; hisobotdagi fayllar ro'yxatini src/ bilan solishtiring.
8.4 V8 va Istanbul raqamlarini solishtirish
Jest (Istanbul) 85 %, Vitest (V8) 88 % — "yaxshilandik" emas, boshqa o'lchov. Bitta usulda qoling.
8.5 Chegara tebranishga yaqin
Chegara 89.6, natija 89.47–89.64 — CI tasodifan qizil. Chegarani haqiqiy qiymatdan biroz past qo'ying (kanon: 85).
9. Mashqlar
1-mashq (oson): hisobotni o'qing
ℹ xatolar.ts | 97.37 | 83.33 | 87.50 | 61-62. Har raqam nimani bildiradi va birinchi navbatda nimani tekshirasiz?
Yechim
Satrlarning 97.37 % yurgan; tarmoqlarning 83.33 %; funksiyalarning 87.5 % (8 tadan 7 tasi, demak bitta funksiya hech chaqirilmagan); yurmagan satrlar — 61–62. Birinchi navbatda 61–62-satrlarni oching: ular aynan chaqirilmagan funksiya bo'lishi mumkin. Keyin tarmoqlar — qaysi if ning qaysi yo'li yurmaganini HTML hisobotda (c8) ko'rish oson.
2-mashq (o'rta): tarmoqni yopish
«Birinchi hisobot» bo'limidagi chegirma.mjs uchun testlarni shunday to'ldiring: satr, tarmoq va funksiya — 100 %. Qancha test kerak bo'ldi? Har test qaysi yo'lni yopadi?
Yechim
test("10 foiz", () => assert.equal(chegirma(35_000, 10), 31_500));
test("0 foiz — narx o'zgarmaydi", () =>
assert.equal(chegirma(35_000, 0), 35_000));
test("noto'g'ri foiz — RangeError", () => {
assert.throws(() => chegirma(1, 101), RangeError);
assert.throws(() => chegirma(1, -1), RangeError);
});
test("yetkazish: chegara", () => {
assert.equal(yetkazish(200_000), 0);
assert.equal(yetkazish(199_999), 15_000);
});To'rtta test. (1) ?: ning rost yo'li. (2) ?: ning yolg'on yo'li. (3) if ning rost yo'li — ikkala shart (< 0 va > 100) alohida, chunki || ning har qismi V8'da alohida tarmoq bo'lishi mumkin. (4) yetkazish ikkala yo'li, aynan chegarada. Biz bu to'plamni yurgizdik: pass 4, chegirma.mjs | 100.00 | 100.00 | 100.00.
3-mashq (qiyin): o'z mutatoringiz
Funksiya matnidan avtomatik mutant yasang. mutantlar(kod) funksiyasi uchta almashtirish qilsin: >= → >, < → <=, + → -. Har mutantda faqat bitta joy o'zgarsin. Funksiya mutant matnlari ro'yxatini qaytarsin. new Function bilan har mutantni funksiyaga aylantiring va «Zaif test, 100 % qamrov» bo'limidagi zaif/kuchli testlar bilan sinang. Kod: "(s) => (s >= 200000 ? 0 : 15000)".
Yechim
const ALMASH = [[">=", ">"], ["<", "<="], ["+", "-"]];
function mutantlar(kod) {
const natija = [];
for (const [eski, yangi] of ALMASH) {
let i = kod.indexOf(eski);
while (i !== -1) {
const m = kod.slice(0, i) + yangi + kod.slice(i + eski.length);
natija.push({ nom: `${eski} → ${yangi} (${i})`, kod: m });
i = kod.indexOf(eski, i + 1);
}
}
return natija;
}
const kod = "(s) => (s >= 200000 ? 0 : 15000)";
const zaif = (f) => f(500000) === 0 && f(50000) > 0;
const kuchli = (f) => f(200000) === 0 && f(199999) === 15000;
for (const m of mutantlar(kod)) {
const f = new Function(`return ${m.kod}`)();
console.log(`${m.nom}: zaif ${zaif(f)}, kuchli ${kuchli(f)}`);
}Konsolda:
>= → > (10): zaif true, kuchli falseFaqat bitta mutant chiqdi: kodda < va + yo'q, => dagi > esa >= emas. Zaif test mutantni o'tkazib yubordi (true — tirik), kuchli test o'ldirdi (false). Haqiqiy vositalar matn emas, kod daraxti (AST) bilan ishlaydi — "a >= b" satr ichida bo'lsa ham adashmaydi. new Function — faqat o'quv misoli; foydalanuvchi kiritgan matn bilan hech qachon ishlatmang — u eval kabi xavfli.
4-mashq: API qadami — v1.0.0
package.json ga test:qamrov skriptini qo'shing va version ni 1.0.0 qiling. npm run test:qamrov — chegaralardan o'tdimi? Hisobotdagi eng past tarmoq qamrovli fayl qaysi? README.md da ishga tushirish, skriptlar va .env o'zgaruvchilari ro'yxatini yozing. npm run check dan keyin kanon xabari bilan commit qiling. Oxirida «Frontend'ni ulash» bo'limidagi 4 o'zgarishni frontend repo'sida qiling va brauzerda tekshiring: vazifa qo'shing, belgilang, sahifani yangilang — holat saqlanib qolsinmi?
Yechim
Kanon natijasi: 97.98 / 89.64 / 93.12 %, chegaralar (95 / 85 / 90) o'tdi, eng past tarmoq — sana.ts (50 %). Sizning raqamlaringiz biroz farq qilishi mumkin (yurishdan yurishga tebranish va o'z testlaringiz). README uchun reja: nima bu (bir gap), talablar (Node ≥ 24), npm ci, npm run dev / start, npm run check, npm run test:qamrov, .env.example dagi o'zgaruvchilar, API.md ga havola. Commit — «API qadami» bo'limidagi buyruq. Frontend: sahifani yangilagandan keyin ham vazifalar va belgilangan holat joyida bo'lishi kerak (kanon A holati). Yangilangach ro'yxat bo'sh yoki eski bo'lsa — Network panelida /v1/vazifalar so'rovining statusiga qarang: 404 — proxy'da /v1 yo'q; konsolda CSP xatosi — connect-src da API manzili yo'q.
10. Real ishda
- CI xizmatlari (Codecov, Coveralls, SonarQube) lcov hisobotini o'qib, har pull request'da "qamrov qanchaga o'zgardi" deb izoh yozadi; ko'p jamoalar "yangi kod qamrovi" ni tekshiradi, umumiy foizni emas.
- Moliya va to'lov kodida (Click, Payme integratsiyasi) tarmoq qamrovi va mutation testing jiddiyroq talab qilinadi — bitta
>=pul demak. - Jest loyihalarida
--coveragevacoverageThreshold— xuddi shu g'oya, Istanbul bilan (Jest). - Intervyu savollari: "Coverage 100 % bo'lsa xato yo'qmi?", "Line va branch coverage farqi?", "Mutation testing nima?", "Qamrov chegarasini qanday tanlaysiz?".
Xulosa
- Coverage — testlar yuritgan kod ulushi: satr, tarmoq (har shart yo'li), funksiya; eng muhimi — tarmoq.
- Node 24:
--experimental-test-coverageva--test-coverage-lines/branches/functions— yetmasa exit 1. vazifalar-api1.0.0: 97.98 / 89.64 / 93.12 %; lekinserver.tshisobotda yo'q, bola jarayon kodi sanalmaydi, tarmoq foizi tebranadi.- V8 (Node, c8, Vitest) va Istanbul (nyc, Jest) — har xil o'lchov; c8 V8 qamrovini HTML/lcov qiladi.
- Coverage "kod ishladi" deydi, "to'g'ri tekshirildi" demaydi: 100 % qamrovli zaif test
>=→>mutantini o'tkazib yubordi. - Frontend ulanishi: 4 o'zgarish (
api.ts,.env.development.local, Vite proxy/v1, CSPconnect-src); dev'da proxy, production'da CORS. - 25-qism tugadi:
vazifalar-apiv1 — 67 test, 6 prod bog'liqlik, Postgres'ga tayyor ombor interfeysi.
Keyingi dars: Konteyner nima va Docker'ni o'rnatish — 26-qism boshlanadi: Postgres'ni o'z kompyuteringizda konteynerda ishga tushirish uchun Docker'ni o'rnatamiz.
Manbalar
- Node.js hujjati: Test runner — Collecting code coverage (v24).
- c8: README (12.x).
- Stryker: Introduction to mutation testing — mutation score.
- Kanon:
natijalar/tajriba/t51-qamrov.txt,natijalar/tekshiruv-51.txt,vazifalar-apiholat 51 (package.json,TESTLAR.md,README.md); frontend ulanishi —t-frontend.txtvafrontend-ulanish.diff.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!