Не пишите модульные тесты ES6 Angular 1.x таким образом!

Работая консультантом, я все чаще сталкивался с этим паттерном в исходниках, которые мне приходилось либо поддерживать, либо работать с ними. Вот почему я твердо верю, что этот подход к кодированию/тестированию является антишаблоном модульного тестирования Angular.

Это делает невозможным повторное использование отдельных компонентов

Допустим, у нас есть следующий код:

Как потребитель вашей библиотеки, как я могу повторно использовать FormComponent самостоятельно?

Ответ: не могу. Я должен написать angular.module('myProject', ['main.app.feature-b']), что означает, что я получаю все остальные артефакты, связанные с этим модулем, включая любые блоки config() или run(), которые могут быть совершенно не связаны с модулем. поведение компонента, который я пытаюсь использовать повторно. На данный момент никакое встряхивание дерева мне не поможет, потому что все зависимости явные.

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

Решение. Поместите все свои компоненты/фильтры/сервисы/поставщики/директивы/… в отдельный модуль, и их можно будет как повторно использовать, так и тестировать изолированно. Один компонент на модуль Angular на файл ES6 (1–1–1).

Кто импортирует свой модуль Angular корневого уровня при модульном тестировании?

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

Если вы использовали приведенное выше решение (1–1–1), вы получите множество модулей, в которых есть только одна вещь. Что делает их тестирование легким и быстрым.

Вы не тестируете то, что, по вашему мнению, тестируете

Допустим, вы пишете модульные тесты для компонентов Angular без использования angular.mock.module. Вы знаете, что код в следующем файле работает:

Но можете ли вы доказать, что TodoService работает?

«А-а-а!» — слышу я ваши слова. «Я уже испытал это!». Нет!

Если у вас нет модульного теста для вышеуказанного файла, у вас нет доказательств того, что TodoService, который использует ваше приложение, является тестируемым TodoService. Другими словами, связь вашего приложения также должна быть протестирована (поскольку она может быть неправильно смонтирована).

Решение: 1–1–1… один компонент на модуль Angular на файл ES6 решит эту проблему. Почему? При подходе 1–1–1 модуль Angular будет содержать проводку, которую использует ваше приложение:

И если ваш тест выглядит так:

… тогда вы можете быть уверены, что тестируемый вами «компонент» — это myComponent, и что это тот же самый компонент, что и ваше приложение фактически используя.

Ошибка повторного использования

Разработчики, выступающие за этот анти-шаблон, часто утверждают, что, поскольку в коде нет ссылок на Angular, его легче использовать повторно. Подскажите, как вы собираетесь переиспользовать этот компонент при переходе на React?:

Этот компонент, хотя и не относится напрямую к Angular, полагается на API-интерфейсы Angular и шаблоны кодирования. Вы не сможете повторно использовать компоненты ES6 Angular в React. Мне жаль сообщать новости.

На самом деле, написать компоненты, которые можно использовать в любом фреймворке, непросто. Веб-компоненты, вероятно, лучший вариант, если ваша цель — повторное использование компонентов, не зависящих от фреймворка.

Не все является кодом Angular

Я не утверждаю, что каждый фрагмент кода, который вы пишете внутри проекта Angular, должен быть заключен в модуль Angular. Может быть код, например библиотека дат или функции сортировки, которые можно использовать независимо от Angular или любого другого фреймворка. В таких случаях пишите их как простые модули ES6 и тестируйте без использования angular.mock.module, потому что это правильно.

tl;dr

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

  1. Это уменьшает возможность повторного использования отдельных компонентов (поскольку зависимости не являются явными, а связь между кодом и именем кода является внешней).
  2. Код, который на самом деле использует ваше приложение, возможно, не был протестирован (поскольку код подключения обычно не тестируется при использовании этого подхода к тестированию).

Я принимаю сумасшедшие таблетки? Дай мне знать :)