Тестировать или не тестировать, техническая перспектива

Определите, что вам нужно проверить, а что можно исключить.

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

Что тестировать или не тестировать.

Общие рекомендации и шаблоны

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

Будь проще

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

Если свободного пространства меньше, вы можете расслабиться при тестировании. Вот почему так важно отдавать приоритет простоте тестирования. Фактически, лучшие практики тестирования JavaScript Йони Голдберга подчеркивают важность золотого правила: ваш тест должен ощущаться как помощник, а не как сложная математическая формула. Другими словами, вы должны быть в состоянии понять цель вашего теста с первого взгляда.

Не усложняйте тесты, они не должны вызывать таких ощущений.

Вы должны стремиться к простоте во всех типах тестов, независимо от их сложности. Фактически, чем сложнее тест, тем важнее его упростить. Один из способов добиться этого — использовать плоский дизайн тестирования, при котором тесты делаются максимально простыми и тестируются только то, что необходимо. Это означает, что каждый тест должен содержать только один тестовый пример, и тестовый пример должен быть сосредоточен на тестировании одной конкретной функциональности или функции.

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

Проверьте, что того стоит

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

Не проверяйте все подряд.

Не тестируйте детали реализации

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

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

Одним из решений этой проблемы является рассмотрение различных типов ваших пользователей. Конечные пользователи и разработчики могут различаться в своих подходах и по-разному взаимодействовать с кодом. При планировании тестов важно учитывать, что пользователи будут видеть или с чем взаимодействовать, и делать тесты зависимыми от этих вещей, а не от деталей реализации.

Например, выбор селекторов, менее подверженных изменениям, может сделать тесты более надежными: атрибуты данных вместо селекторов CSS. Для получения более подробной информации обратитесь к статье Кента К. Доддса по этой теме или следите за обновлениями — статья на эту тему появится позже.

Издевательство: не теряйте контроль

Mocking — это широкая концепция, используемая в модульном тестировании, а иногда и в интеграционном тестировании. Он предполагает создание поддельных данных или компонентов для имитации зависимостей, которые имеют полный контроль над приложением. Это позволяет проводить изолированное тестирование.

Использование макетов в ваших тестах может улучшить предсказуемость, разделение задач и производительность. А если вам нужно провести тест, требующий участия человека (например, проверка паспорта), вам придется скрыть его с помощью макета. По всем этим причинам макеты являются ценным инструментом, на который стоит обратить внимание.

В то же время насмешки могут повлиять на точность теста, поскольку это имитация, а не реальный опыт пользователя. Поэтому вам нужно быть внимательными при использовании макетов и заглушек.

Стоит ли мокить в сквозных тестах?

В общем, нет. Однако иногда насмешки могут спасти жизнь, поэтому давайте не исключать их полностью.

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

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

Особенности тестирования: что можно и что нельзя

Итак, что же включает в себя тест? И есть ли различия между типами тестирования? Давайте подробнее рассмотрим некоторые конкретные аспекты, связанные с основными типами тестирования.

Что входит в состав хорошего модульного теста?

Идеальный и эффективный модульный тест должен:

  • Сконцентрируйтесь на конкретных аспектах.
  • Действуйте независимо.
  • Охватывайте мелкомасштабные сценарии.
  • Используйте описательные имена.
  • Если применимо, следуйте шаблону AAA.
  • Гарантия полного покрытия испытаний.
Сделайте ✅ Не ❌
Делайте тесты как можно меньшими. Тестируйте одну вещь в каждом тестовом примере. Пишите тесты для больших модулей.
Всегда держите тесты изолированными и имитируйте нужные вам вещи, находящиеся за пределами вашего подразделения. Включите другие компоненты или услуги.
Держите тесты независимыми. Полагайтесь на предыдущие тесты или делитесь данными испытаний.
Охватите различные сценарии и пути . Ограничьтесь счастливым путем или максимум отрицательными тестами.
Используйте описательные названия тестов, чтобы вы могли сразу понять, о чем ваш тест. Тестируйте только по имени функции, в результате чего оно недостаточно описательно: testBuildFoo() или testGetId() .
Стремитесь к хорошему покрытию кода или более широкому спектру тестовых примеров, особенно на этом этапе. Тестируйте от каждого класса до уровня базы данных (I/O).

Что входит в состав хорошего интеграционного теста?

Идеальный интеграционный тест также имеет некоторые общие критерии с модульными тестами. Однако есть несколько дополнительных моментов, которые необходимо учитывать. Хороший интеграционный тест должен:

  • Моделирование взаимодействия между компонентами.
  • Опишите реальные сценарии и используйте макеты или заглушки.
  • Учитывайте производительность.
Сделайте ✅ Не ❌
Проверьте точки интеграции: убедитесь, что каждое устройство корректно работает при интеграции друг с другом. Тестируйте каждый модуль по отдельности — для этого и нужны модульные тесты.
Тестируйте реальные сценарии: используйте тестовые данные, полученные на основе реальных данных. Используйте повторяющиеся автоматически сгенерированные тестовые данные или другие данные, которые не отражают реальные варианты использования.
Используйте макеты и заглушки для внешних зависимостей, чтобы сохранить контроль над всем тестом. Создавайте зависимости от сторонних сервисов, например, сетевые запросы к внешним сервисам.
Используйте процедуру очистки до и после каждого теста. Забудьте использовать меры очистки внутри ваших тестов, иначе это может привести к сбоям тестов или ложным срабатываниям из-за отсутствия надлежащей изоляции тестов.

Что входит в состав хорошего сквозного теста?

Комплексное сквозное тестирование должно:

  • Копируйте взаимодействие с пользователем.
  • Охватите жизненно важные сценарии.
  • Охватите несколько слоев.
  • Управление асинхронными операциями.
  • Проверьте результаты.
  • Учитывайте производительность.
Сделайте ✅ Не ❌
Используйте ярлыки на основе API. Узнать больше . Используйте взаимодействия пользовательского интерфейса для каждого шага, включая хук beforeEach .
Используйте процедуру очистки перед каждым тестом. Уделяйте больше внимания изоляции тестов, чем при модульных и интеграционных тестах, поскольку здесь более высокий риск побочных эффектов. Не забывайте убираться после каждого теста. Если вы не очистите оставшееся состояние, данные или побочные эффекты, они повлияют на другие тесты, выполняемые позже.
Рассматривайте сквозные тесты как системные тесты. Это означает, что вам необходимо протестировать весь стек приложения. Тестируйте каждый модуль по отдельности — для этого и нужны модульные тесты.
Используйте минимальное количество насмешек или вообще не используйте их в тесте. Подумайте внимательно, хотите ли вы имитировать внешние зависимости. Сильно полагайтесь на издевательства.
Учитывайте производительность и рабочую нагрузку, например, не перепроверяя большие сценарии в одном тесте. Охватывайте большие рабочие процессы без использования ярлыков.