Эта статья является частью 1 из 2. Если вам нужны более сложные материалы, ознакомьтесь с частью 2!

Я подозреваю, что если вы читаете эту статью, значит, вы прошли через окопы тестирования компонентов в Angular. Если это ты, я чувствую твою боль. Тестировать компоненты в Angular - ТРУДНО, но не обязательно. Трудно найти хорошие ответы для тестирования компонентов Angular. Я говорил об этом с другими разработчиками и слышал много недоразумений.

  • OMG, моя установка TestBed сложнее, чем компонент, который я тестирую? Что я делаю неправильно?!
  • Мой компонент уже находится в модуле, почему мне нужно (повторно) создавать модуль в каждой спецификации?
  • NO_ERRORS_SCHEMA предназначен для предотвращения сообщений об ошибках в шаблонах. Разве я не хочу узнавать об ошибках в моих тестах? Разве не в этом смысл написания тестов?
  • Я всегда создаю компонент тестового хоста в своем тесте, и с ними не всегда легко работать. Можно как-нибудь этого избежать?
  • Мокинг может усложниться, если я использую заглушки провайдера. Могу я заглушить корешок? Есть лучший образец?
  • Я начал писать заглушки компонентов для тестирования, они не совсем безопасны по типу. Иногда использование заглушек заставляет мои тесты проходить, когда они должны терпеть неудачу. Теперь у меня есть сотни заглушек компонентов, и их сложно поддерживать. Это выходит из под контроля!
  • Со всеми этими проблемами ... я обнаружил, что мои тесты не дают мне той уверенности, на которую я надеялся. Стоит ли тестировать в Angular?

Когда я начал работать с Angular, я был немного удивлен, что эти проблемы не были решены сообществом. Давайте их решим.

Введите мелкий рендер. Цели просты:

  • Устранить шаблон
  • Поощрять передовой опыт модульного тестирования
  • ABTS (всегда типобезопасный)

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

Уф !!! Это было много шаблонного. Вот лишь некоторые из проблем:

  • Наш модуль TestBed выглядит очень похожим, если не идентичным, на модуль realNgModule, который я уже добавил MyComponent. Полное дублирование модуля.
  • Поскольку я продублировал свой модуль в своей спецификации, я не уверен, что настоящий модуль был настроен правильно.
  • В своей спецификации я использовал НАСТОЯЩИЕ компоненты и сервисы, а это значит, что я не изолировал компонент, который мне интересно тестировать.
  • Это также означает, что я должен следовать и предоставлять все зависимости этих реальных компонентов модулю TestBed.
  • Мне пришлось создать TestHostComponent, чтобы я мог передавать привязки в свой фактический компонент.
  • Моя TestBed длина стандартного кода превысила мою фактическую длину тестового кода.

Теперь давайте посмотрим на версию тех же тестов с мелкой визуализацией:

Вот в чем разница:

  • Повторно использует (и проверяет) MyModule содержит ваш компонент и все его зависимости.
  • Все компоненты внутри MyModule автоматически имитируют идентичные входы / выходы. Это то, что делает рендеринг «неглубоким».
  • В тестах гораздо меньше шаблонов, что упрощает выполнение тестов.
  • В первом тесте мы решили использовать HTML для рендеринга тестового компонента IN THE SPEC, где его легко найти. У каждой спецификации могут быть разные шаблоны, без проблем.
  • Во втором тесте мы решили не использовать HTML, а сразу перешли к привязкам. Привязки здесь безопасны по типу, и функция emit выходного свойства автоматически отслеживается.

Итак, как мы это сделаем? Сначала давайте посмотрим на тестовую установку. Это просто:

new Shallow(MyComponent, MyModule)

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

shallow.render('<my-component linkText="my text"></my-component>)

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

  • Настройте тестовый модуль, имитируя все вMyModule * кроме * для MyComponent, потому что это то, что мы тестируем.
  • Создайте компонент тестового хоста и вставьте HTML-код шаблона из команды рендеринга.
  • Визуализируйте компонент, обнаружите изменения и верните его в тест.

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

Издевается

Иногда нам нужно издеваться над сервисом. Angular предлагает использовать тестовые двойники, но при мелком рендере встроен mocking.

Первый аргумент метода mock - это то, что вы хотите имитировать, второй аргумент - это Partial<ThingToMock>, поэтому ваши фиктивные свойства и методы являются типобезопасными. Кроме того, любые методы, которые вы добавляете в свой макет, будут автоматически отслеживаться на случай, если вам потребуется сделать на них какие-либо утверждения.

Также распространенной практикой является настройка макетов таким образом, чтобы все тесты в файле использовали одни и те же макеты. Это довольно простая настройка: просто переместите этот mock в блок beforeEach, и все готово.

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

Если вы обратите на это пристальное внимание, то заметите, что призывы к издевательству могут быть цепочкой. Вы можете издеваться над любым количеством вещей в цепочке, а затем просто позвонить render() в конце. Вы также можете имитировать несколько методов / свойств в классе с помощью одного вызова mock().

Есть довольно простой курс 101, но если вы хотите узнать больше:

Я очень увлечен этим, поэтому, если у вас есть какие-либо вопросы, напишите сообщение в разделе проблем в проекте github.

Удачного тестирования!