Написание модульных тестов — непростая задача. Это похоже на написание кода, но с очень специфическими целями, которые вы не часто пишете. Однако с этими подсказками вам будет проще писать удобные и надежные модульные тесты.
Оглавление
- Вступление.
- Подсказка 1. Создавайте шпионов и заглушки в
beforeEach
, восстанавливайте их вafterEach
. - Совет 2. Сделайте тесты независимыми.
- Подсказка 3. Используйте различные ожидания.
- Краткое содержание.
вступление
Все мы знаем, что нам нужно писать тесты. Возможно, у нас даже есть некоторый опыт их написания. Однако написание модульных тестов похоже на искусство. Он требует некоторых хитростей, и нет предела совершенству. Итак, здесь я поделюсь с вами тремя советами, которые сделают их более надежными и ремонтопригодными.
Я буду приводить примеры на основе следующих инструментов: Карма, мокко, чай. Karma — это средство запуска тестов в браузере. Mocha — это тестовая среда, в которой есть примитивы для запуска тестов: describe
, it
и хуки, такие как before
или beforeEach
. Chai — это библиотека утверждений. Однако все подсказки в равной степени применимы и к другим тестовым настройкам, таким как Jest или Web Test Runner.
Подсказка 1: Создавайте шпионов в заглушках в beforeEach
, восстанавливайте их в afterEach
Возьмем, к примеру, следующую особенность. Он делает HTTP-запрос в методе _request
, который нам не нужен в тестах, поэтому мы заглушаем его. stub
позволяет нам определить поведение функции для нашего теста. В нашем примере функция сразу же разрешает возвращенный промис, не выполняя HTTP-запрос. Затем мы проверяем методы requestGet
или requestPost
, чтобы убедиться, что они в конечном итоге вызывают _request
.
Все идет нормально:
Однако через год мы делаем рефакторинг этого кода и случайно пропускаем аргумент.
И результат этого:
Обратите внимание, что оба теста не пройдены. Проблема заключается в потоке выполнения: когда утверждение/ожидание не проходит,тест выполняется останавливается. Поэтому stub.restore
не запускается, что оставляет его нетронутым. Когда мы пытаемся stub
использовать тот же самый метод во втором тесте, sinon
говорит нам, что мы делаем что-то неожиданное (строка 26 в результате).
Итак, первый совет — всегда использовать beforeEach
и afterEach
для создания и восстановления шпионов, заглушек и прочего.
И вот результат этого:
Совет 2. Сделайте тесты независимыми
В некотором смысле, это похоже на предыдущий пункт. В последней подсказке зависимость была введена через общее значение заглушки. Однако, вообще говоря, зависимость между тестами может быть и прямой через общее состояние компонента тестирования.
Напишем следующий пример. Отличие от предыдущего примера в том, что у нашего TestingFeature есть механизм кэширования. Теперь тест будет проверять и этот механизм.
Обратите внимание на следующие шаги:
- Кэширование контролируется флагом
useCache
. - Этот флаг устанавливается только в первом тесте, потому что
testingFeature
распределяется между тестами. - Мы тестируем механизм кэширования, вызывая
requestGet
илиrequestPost
два раза.
И да, пока все хорошо:
Как всегда, еще один год, еще один рефакторинг, еще один баг с отсутствующей строкой «post» в фиче
Результат этого ожидается:
Однако теперь история выглядит так:
- Чтобы отладить это, мы сосредотачиваемся на этом тесте, добавляя к нему
.only
. Ошибка остается. - После некоторого времени отладки мы нашли недостающий аргумент и добавили его.
- А теперь все становится странным. У нас другая ошибка:
Внезапно абсолютно рабочий код дает сбой. Только потому, что мы фокусируемся с .only
на конкретном тесте, предварительное условие состояния не выполняется. Так как он установлен в другом тесте.
Итак, вторая подсказка — полностью подготовить состояние элемента к каждому тесту и проверять его, добавляя .only
к этому тесту во время тестирования. Один из самых простых способов — следовать предыдущей подсказке и добавить весь код подготовки в beforeEach
. Не стесняйтесь создавать дополнительные разделы describe
, чтобы иметь свои собственные разделы beforeEach
и afterEach
.
И результат этого:
Подсказка 3. Используйте различные ожидания
Все библиотеки утверждений имеют множество различных assert
и expect
helpers. Они могут очень помочь понять, что именно ожидается и как не работает тест. Как всегда, пойдем от обратного и сначала увидим «не рекомендуемый» тест.
Результат этого теста прекрасен:
Тем не менее, давайте разрушим ожидания и посмотрим, что произойдет.
Обратите внимание на AssertionError
. Большинство из них заключаются в том, что одно логическое значение не равно другому логическому значению. Но действительно ли это то, что мы пытаемся проверить? Chai предоставляет полный список ожиданий. Давайте проверим, сможем ли мы найти там что-то полезное.
Результат намного понятнее:
Объяснения ошибки теперь соответствуют тому, что произошло на самом деле. Это экономит много времени будущим разработчикам. Если бы они изменили код и увидели неудачные тесты, они бы лучше знали, как это исправить.
В общем, написание тестов — это отдельная тема. Практика делает совершенным, в тестах могут быть ошибки, и их может быть сложно написать.
Тем не менее, благодаря трем советам, приведенным выше, ваши тесты будут лучше сегодня, и в будущем вы и ваши коллеги-разработчики скажут вам спасибо за это.
- Фото Ferenc Almasi на Unsplash
- Тщательный обзор Maarten Stolte, Remco Gubbels и Gabi Wesselman