Node.js'da testlash: node:test

Kod yozgandan keyin uni tekshirasiz: dasturni ishga tushirib, natijani ko’zdan kechirasiz. Funksiya o’nta bo’lsa, har o’zgarishdan keyin o’ntasini qayta tekshirish kerak. Amalda buni hech kim qilmaydi — shuning uchun eski kod buzilgani sezilmay qoladi.

Test aynan shu ishni bajaradi: bitta buyruq bilan hamma tekshiruv avtomatik yuriydi.

Hech narsa o’rnatilmaydi

JavaScript testlash darsida test tushunchasi bilan tanishgansiz. Node.js’da test yurituvchi ichiga qurilgan:

Sinaladigan funksiya

Avval tekshiriladigan kod kerak. slug.js:

function createSlug(title) {
  if (typeof title !== "string") {
    throw new TypeError("title satr bo'lishi kerak");
  }
  return title
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-|-$/g, "");
}

module.exports = { createSlug };

Funksiya sarlavhadan URL uchun qismni yasaydi.

Birinchi test

Test fayli nomi .test.js bilan tugaydi. slug.test.js:

const test = require("node:test");
const assert = require("node:assert");
const { createSlug } = require("./slug");

test("bo'shliqni chiziqchaga almashtiradi", () => {
  assert.strictEqual(createSlug("Node js darsi"), "node-js-darsi");
});

test("bosh va oxirgi chiziqchani olib tashlaydi", () => {
  assert.strictEqual(createSlug("  Salom!  "), "salom");
});

test("satr bo'lmasa xato beradi", () => {
  assert.throws(() => createSlug(42), TypeError);
});

Yuritish:

node --test
✔ bo'shliqni chiziqchaga almashtiradi (1.1955ms)
✔ bosh va oxirgi chiziqchani olib tashlaydi (0.1961ms)
✔ satr bo'lmasa xato beradi (0.6304ms)
ℹ tests 3
ℹ suites 0
ℹ pass 3
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 128.6357

Uchta belgisi — uchta test o’tdi. --test bayrog’i papkadagi test fayllarini o’zi topadi.

Test yiqilganda nima ko’rinadi

Bu muhim: xato xabarini o’qiy bilish kerak. Ataylab noto’g’ri kutilgan qiymat yozamiz:

const test = require("node:test");
const assert = require("node:assert");

function add(a, b) {
  return a + b;
}

test("ikki sonni qo'shadi", () => {
  assert.strictEqual(add(2, 2), 5);
});
node --test
✖ ikki sonni qo'shadi (1.9518ms)
ℹ tests 1
ℹ pass 0
ℹ fail 1

✖ failing tests:

test at fail.test.js:5:1
✖ ikki sonni qo'shadi (1.9518ms)
  AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

  4 !== 5

    actual: 4,
    expected: 5,
    operator: 'strictEqual'

Uch narsa aytilgan: qaysi test, qaysi qator va 4 !== 5. actual haqiqiy natija, expected kutilgani.

Asosiy assert metodlari

Metod Nimani tekshiradi
assert.strictEqual(a, b) a === b — son, satr, mantiqiy qiymat
assert.deepStrictEqual(a, b) Massiv va obyekt ichini solishtiradi
assert.ok(value) Qiymat rostmi
assert.throws(fn, Type) Funksiya xato chiqaradimi
assert.rejects(promise) Asinxron amal rad etiladimi

describe va it bilan guruhlash

Testlar ko’payganda ularni mavzu bo’yicha guruhlash qulay.

storage.js — fayl bilan ishlaydigan modul:

const fs = require("node:fs/promises");

async function saveNotes(filePath, notes) {
  await fs.writeFile(filePath, JSON.stringify(notes, null, 2), "utf8");
}

async function loadNotes(filePath) {
  try {
    const content = await fs.readFile(filePath, "utf8");
    return JSON.parse(content);
  } catch (error) {
    if (error.code === "ENOENT") {
      return [];
    }
    throw error;
  }
}

module.exports = { saveNotes, loadNotes };

storage.test.js:

const { describe, it, after } = require("node:test");
const assert = require("node:assert");
const fs = require("node:fs/promises");
const path = require("node:path");
const { saveNotes, loadNotes } = require("./storage");

const testFile = path.join(__dirname, "test-notes.json");

describe("storage moduli", () => {
  // Test tugagach yaratilgan faylni tozalaymiz
  after(async () => {
    await fs.rm(testFile, { force: true });
  });

  it("fayl yo'q bo'lsa bo'sh ro'yxat qaytaradi", async () => {
    const notes = await loadNotes(path.join(__dirname, "yoq.json"));
    assert.deepStrictEqual(notes, []);
  });

  it("yozgan ma'lumotini qayta o'qiydi", async () => {
    await saveNotes(testFile, [{ id: 1, text: "Salom" }]);
    const notes = await loadNotes(testFile);
    assert.strictEqual(notes.length, 1);
    assert.strictEqual(notes[0].text, "Salom");
  });
});
node --test
▶ storage moduli
  ✔ fayl yo'q bo'lsa bo'sh ro'yxat qaytaradi (6.8637ms)
  ✔ yozgan ma'lumotini qayta o'qiydi (4.7573ms)
✔ storage moduli (14.7798ms)
ℹ tests 2
ℹ suites 1
ℹ pass 2
ℹ fail 0

Uch narsaga e’tibor bering. Birinchidan, testlar guruh ichida chekindi. Ikkinchidan, async funksiya test sifatida ishlaydi — qo’shimcha sozlash kerak emas. Uchinchidan, after testdan keyin tozalash ishini bajardi.

Yordamchi Qachon ishlaydi
before Guruhdagi barcha testlardan oldin bir marta
after Guruhdagi barcha testlardan keyin bir marta
beforeEach Har test oldidan
afterEach Har testdan keyin

Asinxron xatoni tekshirish

Rad etilgan Promise uchun alohida metod bor:

const test = require("node:test");
const assert = require("node:assert");

async function findUser(id) {
  if (typeof id !== "number") {
    throw new TypeError("id son bo'lishi kerak");
  }
  return { id, name: "Aziz" };
}

test("noto'g'ri id da rad etadi", async () => {
  await assert.rejects(() => findUser("salom"), TypeError);
});

test("to'g'ri id da foydalanuvchi qaytaradi", async () => {
  const user = await findUser(7);
  assert.strictEqual(user.id, 7);
});
node --test
✔ noto'g'ri id da rad etadi (1.8021ms)
✔ to'g'ri id da foydalanuvchi qaytaradi (0.3104ms)
ℹ pass 2
ℹ fail 0

assert.rejects oldida await turishi shart — xatolar darsida aytilgan qoida bu yerda ham ishlaydi.

mock — soxta funksiya

Ba’zan funksiya chaqirilganini tekshirish kerak, natijani emas. Masalan, xabar yuborish funksiyasi har element uchun ishladimi?

const { test, mock } = require("node:test");
const assert = require("node:assert");

function sendReport(items, notify) {
  for (const item of items) {
    notify(item);
  }
  return items.length;
}

test("notify har element uchun chaqiriladi", () => {
  const notify = mock.fn();
  const total = sendReport(["a", "b", "c"], notify);

  assert.strictEqual(total, 3);
  assert.strictEqual(notify.mock.callCount(), 3);
  assert.strictEqual(notify.mock.calls[0].arguments[0], "a");
});
node --test
✔ notify har element uchun chaqiriladi (1.3508ms)
ℹ pass 1
ℹ fail 0

Haqiqiy loyihada notify o’rnida xat yuborish turishi mumkin. Mock tufayli test paytida hech kimga xat ketmaydi.

Qamrovni o’lchash

node --test --experimental-test-coverage
ℹ start of coverage report
ℹ ------------------------------------------------------------
ℹ file        | line % | branch % | funcs % | uncovered lines
ℹ ------------------------------------------------------------
ℹ  storage.js |  89.47 |    80.00 |  100.00 | 15-16
ℹ slug.js     | 100.00 |   100.00 |  100.00 |
ℹ ------------------------------------------------------------
ℹ all files   |  93.55 |    88.89 |  100.00 |
ℹ ------------------------------------------------------------
ℹ end of coverage report

Oxirgi ustun eng foydalisi. storage.js da 15-16-qatorlar tekshirilmagan — bu ENOENT dan boshqa xato uchun yozilgan throw tarmog’i.

package.json ga qo’shish

Har safar bayroq yozmaslik uchun buyruqni skriptga yozing:

{
  "name": "node-start",
  "version": "1.0.0",
  "scripts": {
    "test": "node --test",
    "test:coverage": "node --test --experimental-test-coverage"
  }
}
npm test
ℹ tests 3
ℹ pass 3
ℹ fail 0

Skriptlar npm darsida ko’rilgan.

Amaliy mashq

node-start papkasida bajaring:

  1. slug.js ni yozib, unga uchta test qo’shing va node --test bilan yuriting;
  2. Bitta testdagi kutilgan qiymatni ataylab buzib, xato xabaridagi actual va expected qatorlarini o’qing;
  3. Ikki obyektni strictEqual bilan solishtirib ko’ring, so’ng deepStrictEqual ga almashtiring;
  4. storage.js uchun describe va it bilan guruh yozib, after ichida test faylini tozalang;
  5. mock.fn() bilan soxta funksiya yaratib, callCount() ni tekshiring;
  6. --experimental-test-coverage bilan qamrovni o’lchang va tekshirilmagan qatorlarni toping.

2-qadam eng muhimi: test yiqilganda chiqadigan xabarni o’qiy bilish testlar yozishdan kam ahamiyatli emas.

Qisqacha xulosa

  • node:test va node:assert Node.js ichida keladi — paket o’rnatilmaydi.
  • Test fayli .test.js bilan tugaydi, node --test ularni o’zi topadi.
  • strictEqual oddiy qiymatlar uchun, obyekt va massiv uchun deepStrictEqual.
  • describe va it testlarni guruhlaydi, before/after tayyorlash va tozalash ishini bajaradi.
  • async funksiya test sifatida ishlaydi, rad etishni assert.rejects tekshiradi.
  • mock.fn() funksiya necha marta va qanday argument bilan chaqirilganini eslab qoladi.
  • Qamrov hisoboti sinalmagan qatorlarni ko’rsatadi — raqamning o’zi maqsad emas.

Keyingi darsda debug qilish — xatoni console.log siz topish.

Bu dars foydali bo'ldimi?

marta ko'rildi