Jasmine — это популярный фреймворк для тестирования JavaScript, обеспечивающий чистый синтаксис и поддержку поведения, ориентированного на тестирование (Behavior-Driven Development, BDD). Ключевым элементом в организации тестов являются тестовые наборы, которые позволяют структурировать тесты, группировать их по функциональности и управлять зависимостями между ними.
describe и иерархия
тестовОсновным строительным блоком для организации тестов в Jasmine
является функция describe. Она создает тестовый
набор (suite), который может содержать несколько
спеков (specs), реализованных через функцию
it.
describe('Массивы', () => {
it('должен содержать добавленный элемент', () => {
const arr = [];
arr.push(1);
expect(arr).toContain(1);
});
it('должен иметь длину 0 при инициализации', () => {
const arr = [];
expect(arr.length).toBe(0);
});
});
Особенности describe:
describe, создавая
иерархическую структуру тестов.beforeEach,
afterEach) для подготовки состояния перед запуском всех
спеков внутри набора.Jasmine поддерживает вложение describe внутри другого
describe. Это позволяет строить детализированные сценарии и
логически разделять тесты.
describe('Калькулятор', () => {
describe('Сложение', () => {
it('должно правильно складывать положительные числа', () => {
expect(1 + 2).toBe(3);
});
it('должно правильно складывать отрицательные числа', () => {
expect(-1 + -2).toBe(-3);
});
});
describe('Вычитание', () => {
it('должно правильно вычитать положительные числа', () => {
expect(5 - 2).toBe(3);
});
});
});
Преимущества вложенных наборов:
beforeEach
родительского describe выполняется перед хуками дочернего
уровня.Jasmine предоставляет четыре основных типа хуков, используемых внутри
describe:
beforeAll — выполняется один раз перед
всеми спек-тестами набора.afterAll — выполняется один раз после
всех спек-тестов набора.beforeEach — выполняется перед каждым
спек-тестом.afterEach — выполняется после каждого
спек-теста.Пример применения хуков:
describe('Пользовательский сервис', () => {
let service;
beforeAll(() => {
service = new UserService();
});
beforeEach(() => {
service.clearUsers();
});
it('должен добавлять нового пользователя', () => {
service.addUser('Alice');
expect(service.getUsers()).toContain('Alice');
});
it('должен возвращать пустой список после очистки', () => {
expect(service.getUsers().length).toBe(0);
});
});
Особенности:
beforeAll и afterAll используются для
ресурсоемких операций, которые не нужно выполнять перед
каждым тестом.beforeEach и afterEach обеспечивают
изолированное состояние для каждого теста, предотвращая
побочные эффекты.Jasmine поддерживает механизмы временной фокусировки или исключения тестов:
fdescribe — выполняет только этот
набор тестов, игнорируя все остальные.xdescribe — пропускает весь набор
тестов.fit — выполняет только один тест.xit — пропускает отдельный тест.Пример:
fdescribe('Фокус на сложении', () => {
it('проверка 2 + 2', () => {
expect(2 + 2).toBe(4);
});
});
xdescribe('Пропущенные тесты', () => {
it('этот тест не выполняется', () => {});
});
Использование фокусировки удобно при отладке проблемных тестов, а пропуск помогает временно исключить ненужные проверки.
Для крупных проектов рекомендуется использовать следующие подходы к организации тестовых наборов:
describe для каждого модуля или компонента.app/components/Button.js →
spec/components/Button.spec.js).Для организации тестов удобно создавать фабрики объектов и
утилитные функции, чтобы уменьшить дублирование кода внутри
beforeEach:
function createUser(name = 'Default') {
return { name, createdAt: new Date() };
}
describe('User Factory', () => {
let user;
beforeEach(() => {
user = createUser('Alice');
});
it('должен иметь правильное имя', () => {
expect(user.name).toBe('Alice');
});
it('должен содержать дату создания', () => {
expect(user.createdAt).toBeDefined();
});
});
Такой подход повышает читаемость тестов и делает наборы более поддерживаемыми и масштабируемыми.
Jasmine поддерживает тестирование асинхронного кода через
done callback, промисы или
async/await. Хуки также могут быть асинхронными:
describe('Асинхронные операции', () => {
let data;
beforeEach(async () => {
data = await fetchData();
});
it('должен загружать данные', () => {
expect(data).not.toBeNull();
});
});
Использование асинхронных хуков обеспечивает корректное выполнение тестов, которые зависят от внешних ресурсов, без нарушения изоляции наборов.
Эта организация тестовых наборов позволяет создавать логически структурированные, изолированные и легко поддерживаемые тесты, минимизируя дублирование и упрощая управление состоянием в проектах любого масштаба.