Посібник з юніт-тестування в Node.js за допомогою jest

Коли я вперше почав створювати API з використанням Node.js, я не розумів, чому варто писати тести. Чесно кажучи, я вважав це другорядною задачею. Я зосереджувався на правильності логіки і переходив до наступної функції. Написання тестів здавалося часозатратним навантаженням, особливо коли додаток здавався абсолютно справним під час розробки. Однак усе змінилося, коли я відправив свій код у продакшн.

Я пам’ятаю момент, коли я додав просту функцію до мого API і думав, що все достатньо протестовано. Але через кілька тижнів, після деяких оновлень, я отримав скаргу: нова функція не працює для певної групи користувачів. І тільки коли я почав розбиратися з проблемою, я зрозумів, що моє початкове припущення — що все працює — було помилковим. Без правильних тестів, деякі крайні випадки пройшли непоміченими, що призвело до розчарування користувачів.

Ось тоді я зрозумів, як важливо писати тести: це критично важливо. Тести допомагають виявляти ці проблеми на ранніх етапах, економлячи ваш час, нерви та зменшуючи кількість скарг від клієнтів.

У цьому блозі я проведу вас через процес налаштування вашого Node.js додатку для тестування, створення папок для організації тестових файлів і покажу, як тестувати примітивні та референсні типи. Ми використаємо Jest, один з найпопулярніших фреймворків для тестування в Node.js, для перевірки чисел, рядків, масивів і функцій. Наприкінці цього посібника ви зрозумієте, чому юніт-тестування — це не просто добра практика, а необхідність для побудови масштабованих та підтримуваних додатків.

Налаштування вашого Node.js додатку для тестування

Перед тим, як розпочати написання тестів, давайте переконаємося, що ваше середовище Node.js готове до тестування.

1. Встановіть Node.js та Jest

Перший крок — переконатися, що у вас встановлений Node.js. Ви можете завантажити та встановити Node.js з цього посилання. Після налаштування Node.js, створіть новий проєкт і ініціалізуйте його за допомогою npm:

mkdir my-node-app  
cd my-node-app  
npm init -y

Після ініціалізації вашого проєкту, встановіть Jest для тестування:

npm install --save-dev jest

Jest — чудова бібліотека для тестування, яка включає вбудовані матчери і утиліти для запуску юніт-тестів. Після встановлення Jest додайте наступний тестовий скрипт у ваш файл package.json:

"scripts": {  
 "test": "jest"  
}

Тепер ви можете запустити тести за допомогою:

npm test

2. Налаштування структури папок

Після встановлення Jest, настав час налаштувати структуру папок. Правильна структура папок допоможе зберегти організованість і забезпечити масштабованість проєкту з часом.

Ось базова структура папок, яку ви можете використовувати:

my-node-app/  
├── src/  
│ └── app.js  
├── tests/  
│ └── myFirstTest.test.js  
├── package.json  
└── jest.config.js
  • src/: Ця папка буде містити весь вихідний код вашого додатку.
  • tests/: Ця папка буде містити всі тестові файли для вашого додатку.
  • jest.config.js: Тут ви можете налаштувати Jest (якщо потрібно) для власних поведінкових налаштувань або початкових налаштувань.

Написання тестів: від примітивних типів до референсних

Тепер, коли ваш Node.js додаток налаштовано і організовано, давайте перейдемо до тестування.

1. Тестування примітивних типів

У JavaScript примітивні типи включають числа, рядки, булеві значення, null і undefined. Jest надає кілька матчерів, таких як toBe, toBeFalsy і toBeUndefined, для перевірки цих примітивних типів.

Приклад 1: Тестування операцій з числами

Давайте почнемо з тестування базових арифметичних операцій. У цьому прикладі ми перевіримо прості математичні операції, щоб переконатися, що результати правильні.

describe("Тестування операцій з числами", () => {  
 test("повинно додавати два числа", () => {  
 expect(2 + 1).toBe(3); // Простий тест на арифметику  
 });  
 test("не повинно дорівнювати неправильній сумі", () => {  
 expect(9 + 4).not.toBe(10); // Негативний тест  
 });  
});

Пояснення:

  • describe(): Ця функція використовується для групування пов’язаних тестів. Вона приймає два параметри:
  • Опис групи тестів.
  • Функція, що містить тести, які будуть виконані в межах цієї групи.
    Функція зворотного виклику (callback function), яка містить окремі тести.

  • У цьому випадку у нас є блок describe, названий "Тестування операцій з числами", який групує тести, що стосуються операцій з числами.

  • test(): Ця функція визначає окремий тестовий випадок. Вона також приймає два параметри:

  1. Опис тесту (що він перевіряє).
  2. Функція зворотного виклику (callback function), яка містить власну тестову логіку.
  • expect(): Це основа тесту. Функція expect використовується для твердження, що значення відповідає нашим очікуванням. У цьому прикладі ми використовуємо матчер toBe, який перевіряє, чи відповідає фактичне значення очікуваному значенню точно.
  • expect(2 + 1).toBe(3) перевіряє, чи дорівнює результат додавання 2 і 1 числу 3.
  • expect(9 + 4).not.toBe(10) перевіряє, що 9 + 4 не дорівнює 10.

Приклад 2: Тестування хибних значень (включаючи null)

У JavaScript деякі значення вважаються хибними (falsy). До них відносяться 0, false, null, undefined, NaN і порожній рядок "". Jest надає зручний матчер toBeFalsy(), щоб перевірити, чи є значення хибним.

Давайте розглянемо, як ми можемо протестувати ці хибні значення, включаючи null:

describe("Тестування хибних значень", () => {  
 test("повинно перевіряти хибні значення", () => {  
 let b = undefined;  
 let zero = 0;  
 let emptyString = "";  
 let notANumber = NaN;  
 let nullValue = null;  
 expect(b).toBeFalsy(); // перевірка, чи є значення хибним  
 expect(zero).toBeFalsy(); // перевірка, чи є нуль хибним  
 expect(emptyString).toBeFalsy(); // перевірка, чи є порожній рядок хибним  
 expect(notANumber).toBeFalsy(); // перевірка, чи є NaN хибним  
 expect(nullValue).toBeFalsy(); // перевірка, чи є null хибним  
 });  
});

Пояснення:

  • toBeFalsy(): Цей матчер перевіряє, чи є значення хибним (falsy) в JavaScript. Хибні значення включають 0, false, null, undefined, NaN і порожній рядок "".

У цьому тесті:

  • expect(b).toBeFalsy() перевіряє, чи є змінна b (яка дорівнює undefined) хибною.
  • expect(zero).toBeFalsy() перевіряє, чи є 0 хибним значенням.
  • expect(emptyString).toBeFalsy() перевіряє, чи є порожній рядок "" хибним.
  • expect(notANumber).toBeFalsy() перевіряє, чи є NaN хибним.
  • expect(nullValue).toBeFalsy() перевіряє, чи є null хибним значенням.

Приклад 3: Тестування рядків

Рядки є одним з найбільш поширених примітивних типів у JavaScript, і тестування їх значень є важливою частиною перевірки вхідних даних. Ми можемо використовувати Jest, щоб перевірити, чи містить рядок конкретні символи, чи відповідає регулярному виразу, або чи відповідає іншим критеріям.

describe("Тестування рядкових значень", () => {  
 test("повинно містити 'hello' у рядку", () => {  
 let greeting = "Hello, world!";  
 expect(greeting).toMatch(/hello/i); // перевірка, чи містить рядок 'hello', незалежно від регістру  
 });  
 test("не повинно містити 'goodbye' у рядку", () => {  
 let greeting = "Hello, world!";  
 expect(greeting).not.toMatch(/goodbye/i); // перевірка, чи не містить рядок 'goodbye'  
 });  
 test("повинно відповідати точному рядку", () => {  
 let farewell = "Goodbye, friend!";  
 expect(farewell).toBe("Goodbye, friend!"); // точне співпадіння рядка  
 });  
});

Пояснення:

  • toMatch(): Цей матчер використовується для перевірки, чи відповідає рядок регулярному виразу або чи містить певну підстрічку. У цьому прикладі:
  • expect(greeting).toMatch(/hello/i) перевіряє, чи містить рядок "Hello, world!" підрядок "hello", незалежно від регістру.
  • expect(greeting).not.toMatch(/goodbye/i) перевіряє, чи не містить рядок "goodbye", незалежно від регістру.
  • toBe(): Цей матчер перевіряє точну рівність. Він гарантує, що рядок точно відповідає тому, що ми очікуємо, включаючи регістр та пробіли.

Чому використовувати ці матчери?

  • **toBe()** використовується для суворої рівності, що означає перевірку на точну рівність значень (включаючи тип).
  • **not.toBe()** використовується для негативних тестів, щоб перевірити, що значення не дорівнює певному.
  • **toBeFalsy()** та **toBeUndefined()** корисні для перевірки, чи мають змінні конкретні "хибні" або невизначені значення.

2.

Тестування типів за посиланням (Reference Types)

У JavaScript типи за посиланням (reference types) включають об'єкти, масиви та функції.

Під час роботи з типами за посиланням у Jest важливо розуміти концепцію рівності посилань (reference equality). Наприклад, навіть якщо два об'єкти або масиви містять однакові дані, вони все одно вважаються різними, якщо вони не посилаються на той самий об'єкт у пам'яті.

Давайте розглянемо, як тестувати типи за посиланням за допомогою Jest, зосередившись на основних матчерах та важливості рівності посилань.

Приклад 1: Тестування об'єктів за допомогою Jest

Розпочнемо з тестування об'єктів за допомогою таких матчерів Jest, як toEqual та expect.objectContaining().

describe("Тестування рівності посилань для об'єктів", () => {  
 const user = {  
 name: "Aloo",  
 age: 45,  
 };  
 test("повинно повернути об'єкт користувача з віком 45", () => {  
 // Порівняння всього об'єкта  
 expect(user).toEqual({  
 name: "Aloo",  
 age: 45,  
 });  
 // Перевірка, чи містить об'єкт конкретні властивості та типи  
 expect(user).toEqual(  
 expect.objectContaining({  
 name: expect.any(String),  
 age: expect.any(Number),  
 })  
 );  
 });  
});

Пояснення:

  • toEqual(): Цей матчер використовується для порівняння значень всередині об'єкта, а не самого посилання. Він виконує глибоке порівняння рівності, що означає, що перевіряється, чи мають об'єкти однакові властивості та значення.
  • expect.objectContaining(): Це ще один корисний матчер. Він дозволяє перевірити, чи містить об'єкт конкретні властивості або значення. У цьому випадку ми перевіряємо, чи має об'єкт user властивість name, яка є рядком, і властивість age, яка є числом.

Приклад 2: Тестування масивів за допомогою Jest

Масиви в JavaScript також слідують рівності посилань. Давайте подивимося, як ми можемо тестувати масиви за допомогою Jest.

describe("Тестування рівності посилань для масивів", () => {  
 let myArray = ["Apples", "Bananas", "Carrots", "Eggs"];  
 test("масив повинен містити Apples, Bananas, Carrots, Eggs", () => {  
 // Перевірка, чи співпадає весь масив  
 expect(myArray).toEqual(["Apples", "Bananas", "Carrots", "Eggs"]);  
 // Перевірка, чи містить масив "Carrots"  
 expect(myArray).toEqual(expect.arrayContaining(["Carrots"]));  
 // Перевірка, чи містить масив будь-який елемент типу String  
 expect(myArray).toEqual(expect.arrayContaining([expect.any(String)]));  
 });  
});
  • toEqual(): Як і з об'єктами, ми можемо використовувати toEqual(), щоб перевірити, чи мають два масиви однакові елементи в тому ж порядку.
  • expect.arrayContaining(): Цей матчер дозволяє перевірити, чи містить масив конкретні елементи, незалежно від їхнього розташування в масиві. Це особливо корисно, коли ви тестуєте підмножини масиву.
  • expect.any(): У тесті вище ми також використовуємо expect.any(String), щоб підтвердити, що хоча б один елемент у масиві є типом String. Це допомагає перевірити, чи містить масив елементи, що відповідають заданому типу.

Висновок

Тестування — це важлива частина процесу розробки, і з такими інструментами, як Jest, ви можете бути впевненими, що ваш додаток на Node.js працює як очікується. Налаштувавши додаток з правильною конфігурацією та структурою папок, ви зможете легко писати тести для примітивних значень, типів за посиланням та функцій.

З потужними матчерами Jest ви можете писати тести, які перевіряють вашу логіку коду, перевіряють вміст масивів, глибоко порівнюють об'єкти та багато іншого. Це гарантує, що коли ваш додаток зростатиме, ви зможете вносити зміни з упевненістю, знаючи, що ваш код повністю протестований.

Для додаткової інформації про матчери Jest та техніки тестування ознайомтесь з https://archive.jestjs.io/docs/en/22.x/using-matchers

Отже, сміливо налаштовуйте Jest у вашому додатку на Node.js і починайте писати тести для ваших функцій, масивів, рядків та об'єктів. Виконавши ці кроки, ви отримаєте надійний набір тестів, який допоможе підтримувати якість і надійність вашого коду. Бажаю успіхів у програмуванні! 🚀

Перекладено з: A Guide to Unit Testing in Node.js with jest

Leave a Reply

Your email address will not be published. Required fields are marked *