Правка за март 2019 года: большая часть этой статьи посвящена интеграции jest и vue-test-utils в существующее приложение Vue. В настоящее время лучше просто перейти на vue-cli-3, особенно если вы начинаете новый проект или если ваш существующий проект имеет относительно простой процесс сборки. Обычно это безболезненно, и на Medium есть куча статей, посвященных этому вопросу. Однако, если вам действительно нравится редактировать .babelrc файлы, читайте дальше.

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

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

Настройка

В 3YOURMIND мы используем два основных инструмента с открытым исходным кодом, которые являются основополагающими для написания наших модульных тестов: vue-test-utils и Jest. Jest - это библиотека для запуска тестов и утверждений, выпущенная Facebook, а vue-test-utils - это служебная библиотека, которая теперь является официальным предложением команды Vue и сообщества разработчиков ПО с открытым исходным кодом.

Если вы читаете это, я предполагаю, что вы создаете свое приложение Vue с помощью webpack (или подобного). Я начал с простейшего каркаса Vue, который я мог придумать, - шаблона webpack-simple из vue-cli (v2). Отсюда вам нужно добавить vue-test-utils и jest. В вашем терминале запустите:

yarn add --dev @vue/test-utils jest

Теперь мы можем добавить тестовый скрипт в package.json:

”test”: “./node_modules/.bin/jest”

А пока достаточно просто создать папку под названием «test» и поместить туда все. Позже я обрисую разумную структуру папок для более амбициозных приложений. Теперь у нас есть все готово для написания нашего первого модульного теста, так что давайте сделаем это!

Наш первый тест

Чтобы все было согласовано, мы называем наши модульные тесты идентичными компонентам, которые они тестируют. По умолчанию Jest ищет файлы, заканчивающиеся на test.js или spec.js. На данный момент наш единственный компонент - App.vue, поэтому давайте создадим файл в нашей тестовой папке: App.test.js и выполним быструю проверку работоспособности:

Если вы запустите yarn test сейчас, вы должны увидеть несколько красивых зеленых консольных сообщений, информирующих нас о том, что 1 равно 1. Вот краткое описание того, что содержится в этом файле:

Функция описания действительно предназначена для того, чтобы сообщать нам о том, что тестируется. В каждом тестовом файле должен быть только один из них, поскольку мы хотим поддерживать структуру, в которой каждый компонент имеет один набор тестов (в основном группа тестов для одного компонента, утилиты или чего-то еще). Ему передается функция обратного вызова test, которая группирует вместе утверждения (фактические тесты) внутри своей собственной функции обратного вызова.

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

Функция expect утверждает, что определенное условие истинно. Jest предоставляет различные сопоставители для проверки таких вещей, как строгое равенство (toBe), равенство объектов (toEqual) и т. Д. Их так много, что стоит проверить документацию Jest здесь, чтобы узнать больше, которые объясняют их лучше, чем я.

Итак, это был очень быстрый обзор Jest, который тестирует нас. Мы вообще не говорили о vue-test-utils, что позволяет нам тестировать компоненты Vue с помощью Jest. Давай сделаем это сейчас.

Фактическое тестирование компонента Vue

Я создал поистине потрясающий карточный компонент:

Здесь может быть интересно только одно: атрибут data-test в div. Мы будем использовать это для доступа к div в наших тестах вместо классов или идентификаторов, поскольку он не изменится, если мы позже реорганизуем наш CSS. Здесь в этом нет необходимости, поскольку этот компонент уже на 100% идеален.

Прежде чем мы сможем протестировать компоненты Vue, нужно выполнить еще одну настройку. Сначала запустите yarn add--dev babel-jest vue-jest и добавьте в свой package.json следующее:

У вас тоже должен где-то висеть .babelrc файл. Добавьте к этому:

Это позволяет jest делать две вещи: во-первых, анализировать файлы .vue и правильно анализировать import операторы. Остальная часть нашей кодовой базы, вероятно, будет использовать модули ES, но jest работает в Node, поэтому для этого требуются модули CommonJS. Теперь мы можем писать наши тесты, используя тот же синтаксис, что и наши компоненты. Более подробную информацию об этом можно найти в документации jest.

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

Запустите yarn test еще раз, и вы должны убедиться, что все прошло успешно. Очевидно, что это действительно простой случай (и его можно охватить тестированием снимков, о котором я расскажу позже). Более полезно, с некоторыми незначительными изменениями, вы можете проверить, отображается ли определенное количество строк таблицы:

На странице общих советов в документации vue-test-utils есть еще несколько предложений, и я настоятельно рекомендую прочитать ее сейчас. Как и почти вся документация по Vue, она отличная.

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

Этот файл служит одной цели: сообщить eslint о глобальных переменных, которые он не должен отмечать как undefined. Здесь вы также можете переопределить правила линтинга. Если вы не хотите помещать все файлы, связанные с тестами, в одну папку (например, если вы хотите хранить .js файлы и связанные с ними тесты вместе, что особенно полезно для тестирования действий vuex), вы можете применить правила на основе имени файла в ESLint. Вот небольшой фрагмент, который нужно добавить в ваш основной .eslintrc файл, но вы можете узнать больше в документации ESLint.

На следующий вопрос, который задают многие люди: «Что мне тестировать?», ответить нелегко, и я не буду пытаться сделать это здесь. Я перечислил некоторые дополнительные материалы, которые могут оказаться полезными ниже. Однако, если вы уже знаете, вот несколько шаблонов, которые могут вам пригодиться.

Тестирование визуализированного HTML

Быстрый способ проверить визуализированный HTML - это тестирование снимков. Это просто сериализует смонтированный компонент для последующего сравнения, защищая от неожиданных изменений пользовательского интерфейса. Сначала мы запускаем yarn add jest-serializer-vue, а затем добавляем одну строку к нашему package.json в разделе jest:

Теперь мы можем очень просто создать тестовый снимок:

Это просто сериализует HTML, который визуализируется компонентом, для последующего сравнения. Если мы действительно действительно изменим пользовательский интерфейс, мы сможем обновить наши снимки, запустив yarn test -u. Полученные файлы моментальных снимков всегда следует возвращать в систему контроля версий.

Методы тестирования

Методы - идеальный кандидат для модульного тестирования: при правильном написании они зависят только от явных входных данных и должны возвращать предсказуемый результат на их основе. После того, как вы смонтировали свой компонент и назначили его переменной (я использовал идиоматическое имя wrapper), доступ к методам так же прост, как вызов wrapper.vm.someMethod(arg1, arg2). Затем вы можете протестировать свои методы следующим образом:

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

Тестирование вычисленных свойств

Вычисляемые свойства сложнее тестировать, поскольку они полагаются на какой-то неявный ввод (либо контекст, в котором они вызываются, то есть this, либо какое-либо другое состояние в более широкой области, чем функция). Однако они должны быть чистыми функциями, чтобы их вывод можно было легко протестировать. Мы можем установить данные в компоненте Vue, используя методы wrapper.setData или wrapper.setProps. Оба они инициализируют смонтированный компонент данными, которые затем можно использовать для проверки вычисленных свойств. Когда я пишу это, setProps устарел, поэтому правильный шаблон выглядит следующим образом:

Расширенный бонусный мега-веселье

Компонент, который мы тестировали до сих пор, был очень простым: он не взаимодействует с хранилищем vuex, не знает маршрутизации, не зависит от каких-либо внешних библиотек и не полагается на какие-либо API-интерфейсы браузера, которые не работают. t предоставляется Node. Некоторые или все из этих вещей, возможно, потребуется смоделировать в более сложном компоненте или в представлении маршрутизатора.

Мокинг объекта $ route

Одна из самых простых вещей для имитации - это маршрутизатор, или, точнее, объект маршрута, к которому экземпляр Vue имеет доступ. Например, если метод или вычисляемое свойство обращается к this.$route.path, мы можем создать объект с этим свойством и передать его в аргумент options функции монтирования, предоставляемой vue-test-utils.

Мокинг API-интерфейсов браузера

API-интерфейсы браузера также должны подвергаться издевательствам относительно часто. Если компонент полагается на localStorage, нам нужно имитировать это. В 3YOURMIND мы достигаем этого с помощью вспомогательной функции тестирования, которая предоставляет заглушки для обеспечения выполнения тестов.

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

Мокинг магазина Vuex

Мокинг магазина обычно является наиболее трудоемкой частью тестирования компонента Vue. Однако с хорошо спроектированным магазином написать фабричные функции, чтобы сделать имитацию магазина менее болезненной, не составит труда. В качестве хорошего учебника по крупномасштабному дизайну приложений Vue я рекомендую статью моего коллеги Кевина о Medium. С помощью следующих тестов я попытался точно сопоставить структуру реального магазина с макетами. Ниже представлена ​​наивная реализация имитационного магазина в тесте; позже я предложу альтернативу и перечислю ее преимущества.

Этот тест проходит успешно, но выглядит немного многословным. Если бы мы обращались к трем или четырем модулям из компонента (или, что более вероятно, к представлению, которое еще не было реорганизовано на более мелкие части), это быстро стало бы неуправляемым, и наши тестовые файлы стали бы огромными. Вместо того, чтобы имитировать структуру хранилища в CoolCardNaive.test.js файле, давайте абстрагируемся от нее и переместим в служебную программу, которую мы можем импортировать во все наши тесты. Еще одно примечание: мы добавили сюда новую beforeEach функцию. Это сбрасывает хранилище перед каждым тестом, чтобы убедиться, что они независимы друг от друга. Это важное качество при модульном тестировании.

Заводские функции для имитации магазина

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

Вы можете использовать это в своих тестах так:

По сути, вам просто нужно определить фиктивные значения для любых геттеров, на которые опирается тестируемый компонент. Его можно использовать повторно, так как любые геттеры, не имитируемые в вызове функции, возвращают null и не влияют на тестируемый компонент. Любые действия, которые необходимы, просто имитируются с помощью функции Jest jest.fn()mock, и это все, что необходимо, поскольку здесь мы тестируем компонент, а не наши действия. Еще одно преимущество заключается в том, что по мере роста нашего приложения и введения большего количества модулей для каждого теста требуется только одна или две дополнительные строки, вместо того, чтобы каждый раз имитировать форму всего модуля.

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

Бонусный раунд: структура теста

Единственное, что я хотел бы упомянуть, когда дело доходит до структуры, - это соглашения об именах. Мы стараемся, чтобы все было максимально последовательным; например, если у нас есть компонент с именем SomeComponent.vue, его тест всегда будет называться SomeComponent.test.js. Такие мелкие детали, как эта, делают привлечение новых разработчиков максимально безболезненным, что является победой для всех.

Бонусный раунд 2: Nodelectric Boogavue

Установите это как псевдоним в своей оболочке сейчас, и это сэкономит вам часы в будущем: node --inspect-brk node_modules/.bin/jest --runInBand

Теперь вы можете бросить инструкцию отладчика в любом месте ваших тестов, запустить эту команду и перейти к chrome://inspect в Chrome, чтобы открыть инструменты разработки и отладить ваши тесты.

Заключение

Не всем нравится проводить тестирование на работе, но благодаря vue-test-utils оно может быть относительно безболезненным. В завершение я хотел бы порекомендовать еще кое-что, чтобы рассказать о вещах, в которых у меня не было достаточно места (или знаний) для правильного изучения.

Мы не рассматривали здесь тестирование действий Vuex, так как я сконцентрировался на компонентах. Лахлан Миллер написал отличную статью об этом, которую я рекомендую прочитать, как только вы здесь закончите.

Знать, что тестировать, даже важнее, чем быть экспертом в написании самих тестов. В настоящее время я читаю блоги Кента К. Доддса и Рефакторинг Javascript Эвана Бурчарда, которые помогли мне сосредоточиться на тестировании только стоящих вещей и подтвердили, насколько важно хорошее. тестирование стоит на первом месте. В частности, вдохновитель vue-test-utils, Эдд Йербург, недавно написал книгу, которая конкретно описывает тестирование приложений Vue гораздо более подробно, чем я когда-либо мог себе представить. Проверить это.

Этот пост в блоге был написан в сотрудничестве с моим работодателем 3YOURMIND, который ищет разработчиков в Берлине. Мы - признанный стартап в области 3D-печати с растущей командой дружелюбных и знающих разработчиков. Мы используем Vue.js, Django REST Framework, Spring, Docker и многие другие передовые фреймворки и технологии. Вы можете найти вакансии здесь.