Функции beforeEach и afterEach

В тестировании на JavaScript с использованием Jasmine часто возникает необходимость выполнять повторяющиеся действия перед каждым тестом или после него. Для этих целей предназначены функции beforeEach и afterEach. Они обеспечивают чистоту тестового окружения, уменьшают дублирование кода и повышают читаемость тестов.


beforeEach

beforeEach — это функция, которая запускается до выполнения каждого отдельного it-теста внутри блока describe. Она используется для подготовки окружения: инициализации переменных, создания объектов, установки начального состояния приложения.

Синтаксис:

beforeEach(function() {
  // действия, выполняемые перед каждым тестом
});

Пример использования:

describe('Тестирование массива', function() {
  let numbers;

  beforeEach(function() {
    numbers = [1, 2, 3]; // инициализация перед каждым тестом
  });

  it('должен содержать три элемента', function() {
    expect(numbers.length).toBe(3);
  });

  it('должен содержать число 2', function() {
    expect(numbers).toContain(2);
  });
});

В этом примере переменная numbers создаётся заново перед каждым тестом, что предотвращает влияние одного теста на другой.

Особенности beforeEach:

  • Поддерживает асинхронные операции через done или промисы.
beforeEach(function(done) {
  setTimeout(function() {
    numbers = [4, 5, 6];
    done();
  }, 100);
});
  • Может быть вложена в несколько уровней describe. В этом случае выполняются все beforeEach начиная с внешнего блока к внутреннему.
describe('Внешний блок', function() {
  beforeEach(function() {
    console.log('Внешний beforeEach');
  });

  describe('Внутренний блок', function() {
    beforeEach(function() {
      console.log('Внутренний beforeEach');
    });

    it('тест', function() {
      console.log('Тест');
    });
  });
});

Вывод будет:

Внешний beforeEach
Внутренний beforeEach
Тест

afterEach

afterEach запускается после выполнения каждого теста it. Она используется для очистки состояния, сброса данных, удаления созданных объектов или отмены шпионов (spy) и таймеров.

Синтаксис:

afterEach(function() {
  // действия после каждого теста
});

Пример использования:

describe('Работа с DOM', function() {
  let div;

  beforeEach(function() {
    div = document.createElement('div');
    div.id = 'test-div';
    document.body.appendChild(div);
  });

  afterEach(function() {
    document.body.removeChild(div); // очистка после теста
  });

  it('должен содержать элемент с id "test-div"', function() {
    expect(document.getElementById('test-div')).not.toBeNull();
  });
});

Использование afterEach гарантирует, что каждый тест начнется с чистого DOM, независимо от того, что было изменено предыдущими тестами.

Особенности afterEach:

  • Также поддерживает асинхронность через done или промисы.
  • Может быть вложена в несколько уровней describe и выполняется сначала внутренний afterEach, затем внешний.
describe('Внешний блок', function() {
  afterEach(function() {
    console.log('Внешний afterEach');
  });

  describe('Внутренний блок', function() {
    afterEach(function() {
      console.log('Внутренний afterEach');
    });

    it('тест', function() {
      console.log('Тест');
    });
  });
});

Вывод:

Тест
Внутренний afterEach
Внешний afterEach

Комбинированное использование beforeEach и afterEach

Использование обеих функций вместе обеспечивает полный контроль над подготовкой и очисткой тестового окружения.

Пример комплексного сценария:

describe('Работа с объектом пользователя', function() {
  let user;

  beforeEach(function() {
    user = { name: 'Alice', age: 25 };
  });

  afterEach(function() {
    user = null; // очистка
  });

  it('должен иметь имя Alice', function() {
    expect(user.name).toBe('Alice');
  });

  it('должен иметь возраст 25', function() {
    expect(user.age).toBe(25);
  });
});

Такой подход гарантирует, что изменения, внесённые одним тестом, не повлияют на остальные, сохраняя изоляцию тестов — ключевой принцип юнит-тестирования.


Важные рекомендации

  • Не помещать тяжёлые операции внутри beforeEach, если они не нужны для всех тестов — это замедлит выполнение тестов.
  • Использовать afterEach для сброса состояний, особенно при работе с глобальными объектами или DOM.
  • Вложенные describe-блоки позволяют создавать иерархию подготовки и очистки, делая код более структурированным и понятным.

beforeEach и afterEach являются основой организации тестов в Jasmine, позволяя минимизировать повторения, поддерживать чистоту тестового окружения и облегчать сопровождение большого количества тестов.