Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос нашим менторам. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Плохие и хорошие практики тестирования

Тесты, как и любой другой код, можно писать по-разному, в том числе очень плохо. Помимо каких-то общих практик и стандартов кодирования у тестов есть свои особенности, о которых надо знать. В этом уроке мы пройдёмся по некоторым из них.

Взаимное влияние тестов

Одно из ключевых правил: тесты не должны влиять друг на друга. Это значит, что любой тест выполняется так, как будто других тестов не существует в природе.

Нарушить это правило очень просто. Один тест может создать файл, изменить переменную или записать что-то в базу. Если остальные тесты наткнутся на эти изменения, то они могут упасть там, где не должны падать, или наоборот — успешно пройти там, где не должны проходить. Кроме этого, в такой ситуации вводится неопределённость. Такие тесты могут падать эпизодически без видимых на то причин. Например, когда тест запускают изолированно, то он работает, а когда вместе с остальными — падает:

let user;

test('first', () => {
  user = { name: 'Vasya' };
  // ...
});

test('second', () => {
  // Используется пользователь, которого создал другой тест!
  // Этот тест зависит от того, как работает предыдущий тест,
  // и не может работать без последовательного запуска обоих тестов.
  user.name = 'Petya';
});

Особенно часто такая ситуация возникает в тестах, активно взаимодействующих с внешней средой: базой данных или файловой системой. Тестирование побочных эффектов имеет свои хитрости и рассматривается в курсе по продвинутому тестированию.

Условные конструкции в тесте

test('something', () => {
  if (/* что-нибудь */) {
    // Выполняем код одним способом
    // Проверка может быть тут
  } else {
    // Выполняем код другим способом
    // Проверка может быть тут
  }
  // Проверка может быть тут
});

Любое ветвление внутри тестов это фактически несколько тестов в рамках одного теста. От этого надо избавляться и никогда так не писать.

Тест вне тестов

Задача beforeEach — готовить данные и среду для тестирования, а задача test — вызывать код, который тестируется, и проводить проверки. Но иногда разработчики переусердствуют:

let result;

beforeEach(() => {
  // Вызывается тестируемый код. Это противоречит идее beforeEach.
  result = sum(5, 9);
});

test('result', () => {
  // Здесь только проверка
  expect(result).toEqual(14);
});

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

Слишком сильная детализация

Программисты под влиянием голосов из интернета стремятся максимально разносить код по файлам, модулям и функциям. То же самое наблюдается и в тестах. Вместо одного теста, в котором содержатся все необходимые проверки, программист создаёт 5 тестов, в каждом из которых ровно одна проверка:

test('create user', () => {
  const user = { name: 'Mark', age: 28 };

  // Тут код, добавляющий пользователя в базу данных

  expect(user.age).toEqual(28);
});
test('create user 2', () => {
  const user = { name: 'Mark', age: 28 };

  // Тут код, добавляющий пользователя в базу данных

  expect(user.name).toEqual('Mark');
});

Чаще всего, единственным результатом такого разделения будет большее количество кода и усложнение рефакторинга в будущем, когда кода станет по-настоящему много.

Глубокая вложенность

Jest позволяет группировать тесты в блоки describe:

describe('User', () => {
  test('should be valid', () => { /* ... */ });
});

Они помогают структурировать сложные тесты и задать для каждого блока describe свой собственный beforeEach. Хотя такая возможность бывает полезна, но очень легко начать использовать её во вред:

describe('', () => {
  describe('...', () => {
    describe('...', () => {
      test('should be valid', () => { /* ... */ })
    });
  });
});

Глубокая иерархия тестов очень тяжело поддаётся анализу и фиксирует структуру. Из-за этого возникают сложности при добавлении новых проверок. Становится непонятно, к чему она относится. Это проблема любых иерархий, которые рассматривают систему только с одной точки зрения.

Код с тестами писать дольше, чем код без тестов

Это очень интересный вопрос, по которому можно понять, насколько хорошо программист умеет писать тесты. Несмотря на то, что некоторые виды тестирования действительно сложны и требуют дополнительного времени, ежедневные тесты, которые пишутся вместе с кодом, должны приводить к ускорению разработки. И на это есть пять причин:

  • Тесты влияют на дизайн кода. Они помогают выявить неудачные решения намного раньше.
  • Подготовка входных данных может занимать значительное время. С тестами это нужно сделать один раз.
  • Проверка результата работы кода может быть сложной и разнообразной. Тесты позволяют об этом не думать, они сами проверяют, что всё хорошо, включая пограничные случаи.
  • Если в проекте тесты пишутся регулярно, то проще и быстрее делать рефакторинг, так как не придётся проверять вручную другие части кода.
  • Тесты снижают уровень стресса.

Дополнительные материалы

  1. Начинаем писать тесты правильно

<span class="translation_missing" title="translation missing: ru.web.courses.lessons.mentors.mentor_avatars">Mentor Avatars</span>

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят менторы из команды Хекслета или другие студенты.

Для полного доступа к курсу, нужна профессиональная подписка

Профессиональная подписка откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, даст возможность обращаться за помощью к менторам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
115
курсов
892
упражнения
2241
час теории
3196
тестов

Зарегистрироваться

или войти в аккаунт

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 115 курсов, 2000+ часов теории
  • 800 практических заданий в браузере
  • 250 000 студентов

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг».

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Rambler
Логотип компании Bookmate
Логотип компании Botmother

Есть вопрос или хотите участвовать в обсуждении?

Зарегистрируйтесь или войдите в свой аккаунт

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг».