IlmHamroh
JavaScript Full-stack/25-qism. HTTP, Express va REST API51/51-dars18 daqiqa
Mundarija (33)

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=95 kabi — yetmasa exit 1. vazifalar-api 1.0.0: satr 97.98 %, tarmoq 89.64 %, funksiya 93.12 %. Lekin bu raqam "hammasi tekshirilgan" degani emas: server.ts hisobotda 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 --test bilan 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 vazifalar frontend'ini o'z vazifalar-api ingizga 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.

js
// 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;
}
js
// 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):

text
ℹ 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 report

Test 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

bash
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:

text
ℹ 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

json
{
  "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):

text
--- --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:

Eng past tarmoq qamrovi (vazifalar-api 1.0.0)
  • 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:

text
ℹ 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:

  1. server.ts umuman yo'q. Coverage faqat test yuklagan fayllarni hisoblaydi. Hech bir test server.ts ni import qilmaydi (u kirish nuqtasi). Shuning uchun u "0 %" bo'lib emas, umuman yo'q bo'lib qoldi — umumiy foiz shishgan.
  2. Bola jarayondagi kod. jarayon.test.ts ilovani alohida jarayonda yurgizadi (exit 1 ni tekshirish uchun). U jarayonda bajarilgan kod hisobotga kirmaydi — jarayon.ts shuning uchun 62.5 %.
  3. 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):

bash
npx c8 --reporter=text node --test
text
--------------|---------|----------|---------|---------|-------------------
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:

bash
npx c8 --check-coverage --lines 90 node --test
text
ERROR: 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.

js
// 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:

text
zaif: asl true, tirik: >= → >
kuchli: asl true, tirik: yo'q

Zaif 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):

text
--- 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):

bash
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.0

git 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):

ts
// 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:

ts
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| A

Diagrammaga 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
js
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
js
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:

text
>= → > (10): zaif true, kuchli false

Faqat 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 --coverage va coverageThreshold — 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-coverage va --test-coverage-lines/branches/functions — yetmasa exit 1.
  • vazifalar-api 1.0.0: 97.98 / 89.64 / 93.12 %; lekin server.ts hisobotda 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, CSP connect-src); dev'da proxy, production'da CORS.
  • 25-qism tugadi: vazifalar-api v1 — 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

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Test coverage va sifat metrikalari: node:test qamrovi, c8 va mutation testing — IlmHamroh