Пошук уроків, статей та іншого контенту
Налаштуєте вимірювання покриття Jest, проаналізуєте звіт і визначите неперевірені гілки коду.
Покриття коду показує, які частини застосунку були виконані під час запуску тестів. Jest може вимірювати кілька типів покриття:
Statements — окремі інструкції виконано;
Branches — гілки умов виконано, наприклад if і else;
Functions — функції викликано;
Lines — рядки коду виконано.
Для NestJS покриття зазвичай вимірюють під час запуску unit-тестів Jest.
Високий відсоток покриття не гарантує відсутність помилок. Він лише показує, який код виконався. Тести все одно мають перевіряти правильність результатів.
У NestJS-проєкті Jest зазвичай уже налаштований. Перевірте скрипти в package.json:
{
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage"
}
}Після цього запустіть:
npm run test:covАбо без додавання окремого скрипту:
npm test -- --coverageJest:
запустить тести;
збере інформацію про виконані частини коду;
виведе підсумок у термінал;
створить каталог coverage зі звітом.
Приклад підсумку:
----------------|---------|----------|---------|---------|
File | % Stmts | % Branch | % Funcs | % Lines |
----------------|---------|----------|---------|---------|
All files | 90 | 66.66 | 100 | 90 |
price.service.ts | 90 | 50 | 100 | 90 |
----------------|---------|----------|---------|---------|Щоб Jest збирав покриття для файлів застосунку, навіть якщо деякі з них не імпортуються тестами, використовуйте collectCoverageFrom.
У NestJS-проєкті конфігурація Jest часто знаходиться в package.json:
{
"jest": {
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s",
"!**/*.spec.ts",
"!**/main.ts"
],
"coverageDirectory": "../coverage",
"coverageReporters": ["text", "text-summary", "html"],
"testEnvironment": "node"
}
}Основні параметри:
collectCoverageFrom — визначає, які файли враховувати у звіті;
!**/*.spec.ts — виключає самі файли тестів;
!**/main.ts — виключає точку запуску застосунку, якщо вона не тестується unit-тестами;
coverageDirectory — каталог для результатів;
coverageReporters — формати звіту;
testEnvironment — середовище виконання тестів.
Для unit-тестів сервісів і контролерів зазвичай достатньо середовища node.
Створимо сервіс, який повертає ціну товару. Для учасника програми лояльності застосовується знижка, а для інших клієнтів ціна залишається без змін.
// price.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class PriceService {
calculate(price: number, isMember: boolean): number {
if (price < 0) {
throw new Error('Ціна не може бути від’ємною');
}
if (isMember) {
return price * 0.9;
}
return price;
}
}У методі calculate є кілька можливих шляхів виконання:
ціна від’ємна — виникає помилка;
ціна невід’ємна, клієнт є учасником — застосовується знижка;
ціна невід’ємна, клієнт не є учасником — повертається початкова ціна.
// price.service.spec.ts
import { PriceService } from './price.service';
describe('PriceService', () => {
let service: PriceService;
beforeEach(() => {
service = new PriceService();
});
it('застосовує знижку для учасника програми', () => {
expect(service.calculate(100, true)).toBe(90);
});
it('відхиляє від’ємну ціну', () => {
expect(() => service.calculate(-10, false)).toThrow(
'Ціна не може бути від’ємною',
);
});
});Запустіть тест із покриттям:
npm run test:covТести успішні, але гілка для звичайного клієнта ще не виконувалася. Рядок:
return price;не був досягнутий під час тестів.
У звіті це може відобразитися як неповне покриття гілок:
File | % Stmts | % Branch | % Funcs | % Lines |
-----------------|---------|----------|---------|---------|
price.service.ts | 88.88 | 75 | 100 | 88.88 |Точні значення можуть відрізнятися залежно від версії Jest, TypeScript і конфігурації проєкту.
Текстовий звіт допомагає швидко знайти файли з низьким покриттям. Для детального аналізу відкрийте HTML-звіт:
coverage/lcov-report/index.htmlУ звіті можна:
переглянути список файлів;
відкрити конкретний файл;
побачити виконані рядки;
побачити рядки, які не виконувалися;
знайти неперевірені гілки умов.
Зазвичай кольори інтерфейсу означають:
зелений — код виконано;
червоний — код не виконано;
жовтий — виконано лише частину гілок.
Для пошуку проблемної умови спочатку дивіться на колонку Branches. Низьке покриття інструкцій не завжди означає, що відсутній окремий тест на кожен сценарій, але низьке покриття гілок прямо вказує на неперевірені варіанти логіки.
Додайте тест для клієнта, який не є учасником програми:
// price.service.spec.ts
import { PriceService } from './price.service';
describe('PriceService', () => {
let service: PriceService;
beforeEach(() => {
service = new PriceService();
});
it('застосовує знижку для учасника програми', () => {
expect(service.calculate(100, true)).toBe(90);
});
it('повертає початкову ціну для звичайного клієнта', () => {
expect(service.calculate(100, false)).toBe(100);
});
it('відхиляє від’ємну ціну', () => {
expect(() => service.calculate(-10, false)).toThrow(
'Ціна не може бути від’ємною',
);
});
});Тепер кожен основний шлях методу виконується тестами:
помилка для від’ємної ціни;
знижка для учасника;
початкова ціна для звичайного клієнта.
Знову запустіть:
npm run test:covПокриття гілок для цього сервісу має зрости, оскільки обидва результати внутрішньої умови if (isMember) тепер перевіряються.
Jest може завершуватися з помилкою, якщо покриття стане нижчим за визначений поріг. Це допомагає не допустити поступового погіршення якості тестів.
Приклад конфігурації:
{
"jest": {
"collectCoverageFrom": [
"**/*.(t|j)s",
"!**/*.spec.ts",
"!**/main.ts"
],
"coverageThreshold": {
"global": {
"statements": 80,
"branches": 75,
"functions": 80,
"lines": 80
}
}
}
}У цьому прикладі Jest очікує:
щонайменше 80% покриття інструкцій;
щонайменше 75% покриття гілок;
щонайменше 80% покриття функцій;
щонайменше 80% покриття рядків.
Якщо фактичне покриття буде нижчим, команда тестування завершиться з помилкою.
Порогові значення потрібно встановлювати реалістично. Надто високий поріг може змусити додавати формальні тести, які не перевіряють корисну поведінку.
Під час аналізу звіту дійте послідовно:
Знайдіть файли з низьким значенням Branches.
Відкрийте файл у HTML-звіті.
Знайдіть підсвічені умови та рядки.
Визначте, який сценарій не був виконаний.
Додайте тест із вхідними даними для цього сценарію.
Переконайтеся, що тест перевіряє результат, а не лише виконує код.
Повторно запустіть покриття.
Наприклад, для умови:
if (isMember) {
return price * 0.9;
}
return price;потрібні тести як для isMember = true, так і для isMember = false.
Виконання рядка не означає, що перевірено всі варіанти його логіки. Для умов важливо дивитися на Branches, а не лише на Lines.
Якщо метод може викинути помилку, потрібно перевірити і невалідні вхідні дані. Інакше гілка обробки помилки залишиться неперевіреною.
Такий тест виконує код, але не підтверджує його поведінку:
it('викликає метод', () => {
service.calculate(100, true);
});Краще перевіряти результат:
it('застосовує знижку', () => {
expect(service.calculate(100, true)).toBe(90);
});Файли запуску застосунку, конфігурації або згенеровані файли можуть штучно знижувати покриття. Визначайте область вимірювання через collectCoverageFrom, але не виключайте бізнес-логіку лише для покращення показника.
Високе покриття не замінює якісних перевірок. Важливіше покрити значущі сценарії:
звичайний результат;
помилки;
граничні значення;
кожну суттєву гілку бізнес-логіки.
Покриття Jest показує, який код виконався під час тестів.
Основні метрики — Statements, Branches, Functions і Lines.
Для запуску вимірювання використовуйте npm run test:cov або прапорець --coverage.
collectCoverageFrom визначає файли, які потрапляють до звіту.
HTML-звіт допомагає знайти конкретні неперевірені рядки та гілки.
Для кожної умови потрібно перевіряти всі суттєві результати її виконання.
coverageThreshold дозволяє встановити мінімальний рівень покриття.
Покриття є інструментом аналізу тестів, а не гарантією відсутності помилок.