Testlash (Jest)

Coverage va yaxshi amaliyot

Test yozishni bilish โ€” bir masala, yaxshi test yozish โ€” boshqa masala. Bu darsda kod qamrovini o'lchash, testlarni to'g'ri tuzilish namunasida yozish va qaysi holatlarni tekshirish kerakligini o'rganamiz.

Kod qamrovi (coverage)

Coverage (qamrov) โ€” bu testlaringiz kodning qancha qismini ishga tushirganini ko'rsatadigan o'lchov. Jest buni --coverage bayrog'i bilan hisoblab beradi:

npx jest --coverage

# package.json scripts'iga qo'shsa ham bo'ladi:
# "test:coverage": "jest --coverage"

Natijada jadval chiqadi. U to'rt ustunni ko'rsatadi:

-----------|---------|----------|---------|---------|
File       | % Stmts | % Branch | % Funcs | % Lines |
-----------|---------|----------|---------|---------|
narx.js    |   100   |    80    |   100   |   100   |
-----------|---------|----------|---------|---------|
Coverage โ€” foydali, lekin aldamchi o'lchov. 100% qamrov kod xatosiz degani EMAS. Test satrni ishga tushirishi mumkin, lekin natijani hech tekshirmasligi mumkin. Coverage'ni maqsad emas, yo'l-yo'riq sifatida ishlating.
Eng foydali ustun โ€” % Branch. U ifning ham rost, ham yolg'on yo'llari tekshirilganini ko'rsatadi. Ko'p yashirin xatolar aynan tekshirilmagan tarmoqlarda yashiringan bo'ladi.

AAA namunasi

Yaxshi test aniq tuzilishga ega bo'lishi kerak. Eng ommabop namuna โ€” AAA (Arrange-Act-Assert), ya'ni Tayyorla-Bajar-Tekshir. Har bir test uch qismga bo'linadi:

  1. Arrange (Tayyorla): kerakli ma'lumot va holatni tayyorlaysiz.
  2. Act (Bajar): tekshirilayotgan funksiyani bir marta chaqirasiz.
  3. Assert (Tekshir): natija kutilganidek ekanini tekshirasiz.
test('savatdagi mahsulotlar umumiy narxini hisoblaydi', () => {
  // Arrange โ€” tayyorlash
  const savat = [
    { nom: 'olma', narx: 100, soni: 2 },
    { nom: 'nok',  narx: 200, soni: 1 }
  ];

  // Act โ€” bajarish
  const jami = umumiyNarx(savat);

  // Assert โ€” tekshirish
  expect(jami).toBe(400);
});
AAA namunasi testni o'qilishi oson qiladi: kim o'qisa ham, nima tayyorlangani, nima bajarilgani va nima kutilayotgani darhol ko'rinadi.

Nimani test qilish kerak?

Hamma narsani testlash kerak emas. Diqqatni eng ko'p xato yashiringan joylarga qarating:

Aksincha, bularni odatda alohida testlashning ma'nosi kam:

Har bir if uchun kamida ikkita test o'ylang: shart rost bo'lgan va yolg'on bo'lgan holatlar. Shunda tarmoqlar to'liq qoplanadi.

Yaxshi test belgilari

Yaxshi testlar bir necha xususiyatga ega. Ularni FIRST tamoyillari deb ham atashadi:

Bundan tashqari, quyidagi amaliy maslahatlarga rioya qiling:

Bir-biriga bog'liq testlar โ€” eng ko'p uchraydigan muammo. Agar bitta test ikkinchisidan qolgan holatga tayansa, biri o'zgarganda ikkinchisi tushunarsiz sabab bilan yiqiladi.

To'liq misol: valyuta konvertori

Endi barcha o'rganganlarimizni bitta funksiya uchun to'liq testda birlashtiramiz. Mana tekshiriladigan funksiya:

// konvertor.js
function konvertQil(summa, kurs) {
  if (typeof summa !== 'number' || typeof kurs !== 'number') {
    throw new Error('Summa va kurs son bo'lishi kerak');
  }
  if (summa < 0) {
    throw new Error('Summa manfiy bo'lishi mumkin emas');
  }
  return Math.round(summa * kurs * 100) / 100;
}

module.exports = { konvertQil };

Uning uchun oddiy, chegaraviy va xato holatlarni qamrab oluvchi to'liq test to'plami:

// konvertor.test.js
const { konvertQil } = require('./konvertor');

describe('konvertQil', () => {

  // Oddiy holat
  test('summani kursga ko'paytiradi', () => {
    // Arrange / Act
    const natija = konvertQil(100, 12.5);
    // Assert
    expect(natija).toBe(1250);
  });

  test('natijani ikki xonagacha yaxlitlaydi', () => {
    expect(konvertQil(10, 1.005)).toBe(10.05);
  });

  // Chegaraviy holatlar
  test('0 summa uchun 0 qaytaradi', () => {
    expect(konvertQil(0, 12.5)).toBe(0);
  });

  test('kurs 0 bo'lsa 0 qaytaradi', () => {
    expect(konvertQil(100, 0)).toBe(0);
  });

  // Xato holatlar
  test('manfiy summa uchun xato tashlaydi', () => {
    expect(() => konvertQil(-5, 12)).toThrow('manfiy');
  });

  test('son bo'lmagan kirish uchun xato tashlaydi', () => {
    expect(() => konvertQil('100', 12)).toThrow();
    expect(() => konvertQil(100, null)).toThrow();
  });
});

E'tibor bering: test to'plami funksiyaning har bir tarmog'ini โ€” oddiy ishlash, yaxlitlash, nol qiymatlar, manfiy va noto'g'ri turdagi kirishlarni โ€” qamrab oldi. Aynan shunday testlar kelajakda kod o'zgartirilganda sizni himoya qiladi.

To'liq testni bir zumda emas, bosqichma-bosqich yozing: avval oddiy holat, so'ng chegaraviy, oxirida xato holatlari. Har bir test qo'shilgach uni ishga tushirib, yashil ekaniga ishonch hosil qiling.

Xulosa