Автор оригинала: FreeCodeCamp Community Member.
Сарха Дайн
В Создайте свой первый компонент Vue.js Мы сделали звездный рейтинг компонента. Мы охватываем множество фундаментальных концепций, чтобы помочь вам создать более сложные компоненты Vue.js.
Тем не менее, есть одна важная точка, необходимая вами для создания бюллетежных компонентов, которые вы можете использовать в производстве: Устройство тестирования Отказ
Почему блок тестирует компонент?
Агрегатные тесты – это решающий Часть непрерывной интеграции. Они делают ваш код намного более надежнее, сосредоточив внимание на небольших изолированных объектах и убедившись, что они всегда ведут себя как ожидалось. Вы можете уверенно повторить свой проект без боязни сломать вещи.
Установка тестов не ограничивается сценариями. Все, что мы можем тестировать в изоляции, является блок, реализуемый, если вы уважаете несколько хороших практик. Эти практики включают в себя одностороннюю, предсказуемость и свободную связь.
Как многоразовые объекты нашего приложения, Компоненты Vue.js являются отличными кандидатами для тестирования подразделения Отказ Мы проверим тот, который мы сделали как единое целое с различными входами и взаимодействиями пользователя, и убедитесь, что он всегда ведет себя так, как мы ожидаем.
Прежде чем начать
Несколько вещей изменились с момента Первоначальное учебное пособие Отказ Vue CLI 3 был выпущен. Vue Test Utils – Официальная библиотека для тестирования модулей Vue.js – созрела на бета-версию. В первом руководстве мы использовали WebPack-Simple , шаблон прототипирования, который не включает в себя функции тестирования. По этим причинам самая простая вещь, чтобы вытереть шифер очистить и перенести проект из учебника до более поздней установки Vue.js.
Я повторно создал проект с первого урока, чтобы вы могли загрузить его прямо из Github Отказ Затем перейдите к распакованному каталогу и установите зависимости.
Примечание: Убедитесь, что вы устанавливаете Node.js Прежде чем идти дальше:
cd path/to/my/project npm install
Затем запустите проект:
npm run serve
Vue Test Utils и jest
Для этого учебника мы будем использовать Vue Test Utils Официальный тестирование Vue.js, наряду с Jest , бегун теста JavaScript, поддерживаемый Facebook.
Vue Test Utils позволяет устанавливать компоненты Vue в изоляции и моделировать взаимодействия пользователя. Он имеет все необходимые утилиты для тестирования односиловых компонентов, включая те, которые используют Vue Router или Vuex.
Jest – это полнофункциональный тестовый бегун, который требует практически нет конфигурации. Он также предоставляет встроенный заявитель библиотеки.
Vue CLI 3 (который я использовал для создания котельной ) позволяет выбрать свой любимый тестовый бегун и устанавливает его для вас. Если вы хотите использовать другой тестовый бегун (например Mocha ), установите Vue CLI 3 и генерировать свой собственный стартовый проект. Тогда вы можете перенести исходные файлы из Моя котельная прямо в этом.
Что мы должны проверить?
Общий подход к тестированию подразделения – Фокус только на публике API (ака черное ящик тестирование). С видом на детали реализации вы разрешаете менять внутренние органы, без необходимости адаптировать тесты. Ведь то, что вы хотите сделать, это Убедитесь, что ваш публичный API не сломается Отказ То, что происходит под капотом, косвенно проверяется, но все, что имеет значение для общественного API, чтобы оставаться надежным.
Это также официальная рекомендация от Vue Test Utils Guides Отказ Поэтому мы только проверим то, что мы можем получить доступ с внешней стороны компонента:
- взаимодействия пользователя
- реквизит меняется
Мы не будем напрямую тестировать вычисленные свойства, методы или крючки. Они будут неявно протестированы путем тестирования общедоступного интерфейса.
Настройка файла спецификации
Как и с регулярными тестами, каждый компонент имеет SPEC-файл, который описывает все тесты, которые мы хотим запустить.
Specs – это файлы JavaScript. По соглашению они имеют то же имя, что и компоненты, которые они тестируют, плюс A .spec
суффикс.
Продолжай и создайте Тест/блок/Рейтинг.spec.js
файл:
// Rating.spec.js
import { shallowMount } from '@vue/test-utils'import Rating from '@/components/Rating'
describe('Rating', () => { // your tests go here})
Мы импортировали наши Рейтинг
Компонент и MOLLOWORMONT
Отказ Последнее является функцией Vuue Test Utils, которая позволяет нам установить наш компонент без монтажа своих детей.
Опишите
Функция вызовов оборачивает весь тест, который мы собираемся написать – он описывает наши Тестирующая Люкс Отказ Он имеет свой собственный объем, и сама может обернуть другие вложенные люксы.
Достаточно сказано, Давайте начнем писать тесты Отказ
Определение сценариев тестирования
Когда мы смотрим на Рейтинг
Снаружи мы можем видеть, что это делает следующее:
- Он оказывает список звезд, равных значениям
MaxStars
опоры пользователю проходит - Это добавляет
Активный
класс к каждой звезде, индекс которой ниже или равнозвезды
опоры пользователю проходит - Он переключает
Активный
Класс на звезде, когда пользователь нажимает на него и удаляет его на следующих звездах - Он переключает иконы
звезда
извезда - о
Когда пользователь нажимает звезду - Это делает счетчик, если пользователь устанавливает
HasCounter
оперитьправда
, скрывает его, если они наберут это наложь
И проявляет текст, говорящий, сколько звезд максимального количества звезд в настоящее время активно.
Обратите внимание, что мы только смотрим на то, что делает компонент снаружи. Нам все равно, что нажатие на звезду выполняет Оценить
метод или что внутренний звезды
Изменения свойства данных. Мы могли переименовать их, но это не должно нарушать наши тесты.
Наш первый тест
Давайте напишем наш первый тест. Нам сначала нужно вручную установить наш компонент с MOLLOWORMONT
и храните его в переменной, на которой мы будем выполнять утверждения. Мы также можем пройти реквизиты через пропсдата
атрибут, как объект.
Установленный компонент представляет собой объект, который поставляется с горсткой полезных методов полезности:
describe('Rating', () => { const wrapper = shallowMount(Rating, { propsData: { maxStars: 6, grade: 3 } }) it('renders a list of stars with class `active` equal to prop.grade', () => { // our assertion goes here })})
Тогда мы можем написать наше первое утверждение:
it('renders a list of stars with class `active` equal to prop.grade', () => { expect(wrapper.findAll('.active').length).toEqual(3)})
Давайте проанализируем то, что здесь происходит. Во-первых, мы используем jest’s ожидать Функция, которая принимает значение, которое мы хотим проверить как аргумент. В нашем случае мы называем Findall Метод на нашем обертка
Чтобы получить все элементы с Активный
класс. Это возвращает Wrapperarray , который является объектом, который содержит массив Обертки Отказ
А Wrapperarray
имеет два свойства: обертки
(содержащиеся обертки
) и Длина
(количество обертки
). Последнее это то, что нам нужно иметь ожидаемое количество звезд.
ожидать
Функция также возвращает объект, на котором мы можем вызывать методы для проверки прошедшего значения. Эти методы называются Соответствует Отказ Здесь мы используем Товарищ
Соответствует и пропустите его ожидаемое значение как в аргументах. Метод возвращает логическое значение, что является то, что проверку ожидает, либо проходит или сбой.
Подводя итоги, здесь мы говорим, что мы ожидаем общий объем элементов с классом Активный
В нашей оболочке мы находим равную 3 (значение, которое мы присваивали на класс
опора).
В вашем терминале запустите свой тест:
npm run test:unit
Вы должны увидеть это пройти?
Время написать еще немного.
Имитация пользовательского ввода
Vue Test Utils позволяет легко имитировать, какие реальные пользователи заканчиваются в производстве. В нашем случае пользователи могут нажать на звезды, чтобы переключить их. Мы можем подделать это в наших тестах с триггер
Метод и отправляйте все виды событий.
it('adds `active` class on an inactive star when the user clicks it', () => { const fourthStar = wrapper.findAll('.star').at(3) fourthStar.trigger('click') expect(fourthStar.classes()).toContain('active')})
Здесь мы сначала получим нашу четвертую звезду с Findall
и на , который возвращает Обертка
от Wrapperarray
при прохожденном индексе (нулевое нумерация). Тогда мы смоделируем Нажмите
Мероприятие на нем – мы подражаем к действию от пользователя, который щелкнул бы или нажал на четвертую звезду.
Так как мы устанавливаем класс
SPOP TO 3, четвертая звезда должна быть неактивной, прежде чем мы нажимаем, поэтому событие Click должно быть активно. В нашем коде это представлено классом Активный
Что мы добавляем на звезды только тогда, когда они активируются. Мы проверяем это, позвонив Классы Способ на звезде, который возвращает имена классов как массив строк. Тогда мы используем TOCONTAIN Matcher, чтобы убедиться, что Активный
класс здесь.
Настройка и разрыв
Поскольку мы вызвали щелчок нашего компонента, мы мутировали его состояние. Проблема в том, что мы используем тот же компонент для всех наших тестов. Что произойдет, если мы изменим заказ наших тестов и переместите эту первую позицию? Тогда второй тест потерпит неудачу.
Вы не хотите полагаться на хрупкие вещи, такие как порядок, когда речь идет о тестах. Тестовый набор должен быть надежными, а существующие тесты должны в идеале не изменяться, если вы не нарушаете API.
Мы хотим убедиться, что у нас всегда есть предсказуемая обертка для выполнения утверждений. Мы можем достичь этого с функциями настройки и разрыва. Это помогают, которые давайте инициализируем вещи, прежде чем мы запустим тесты, и потом убираем.
В нашем случае способ сделать это может быть создать нашу обертку перед каждым тестом и уничтожить его потом.
let wrapper = null
beforeEach(() => { wrapper = shallowMount(Rating, { propsData: { maxStars: 6, grade: 3 } })})
afterEach(() => { wrapper.destroy()})
describe('Rating', () => { // we remove the `const wrapper = …` expression // …}
Как предполагают их имена, Rebedeach и ДОПОЛЮЧЕНИЕ пройти до и после каждого теста соответственно. Таким образом, мы можем быть на 100% уверены, что мы используем свежую обертку, когда мы запускаем новый тест.
Специальные идентификаторы для тестов
Никогда не очень хорошая идея смешивать селекторов для укладки и других целей, таких как тестовые крюки.
Что делать, если вы измените имя тега или класс?
Что, если у вас нет конкретного идентификатора на элементе, который вы хотите проверить, например, в нашем случае, счетчик?
Вы не хотите загрязнять ваш производственный код с классами, которые будут там бесполезны. Было бы намного лучше иметь выделенные крючки для тестов, таких как выделенный атрибут данных, Но только во время испытаний Отказ Таким образом, беспорядок не оставлен в финальной сборке.
Один из способов справиться с этим – создать Пользовательская Vue Directive Отказ
Экземпляр VUE имеет Директива
Метод, который принимает два аргумента – A Имя и Объект функций для каждого Крюк компонента жизненного цикла при введении в доме. Вы также можете пройти одну функцию, если вы не заботитесь о конкретном крючке.
Давайте создадим новый каталог под названием Директивы
в SRC/
и добавьте test.js
файл. Мы экспортируем функцию, которую мы хотим пройти в нашей директиве.
// test.js
export default (el, binding) => { // do stuff}
Директивой крючок может занять Несколько аргументов И, в нашем случае нам нужны только первые два: Эль
и Привязка
Отказ Эль
Аргумент относится к элементу. Директива обязана. Привязка
Аргумент – это объект, который содержит данные, которые мы передали в Директиве. Таким образом, мы можем манипулировать элементом, как нам нравится.
export default (el, binding) => { Object.keys(binding.value).forEach(value => { el.setAttribute(`data-test-${value}`, binding.value[value]) })}
Мы передаем объект к нашей директиве, поэтому мы можем генерировать атрибуты данных, начиная с Тест данных-
Отказ В функции обработчика мы идете за каждую свойство Привязка
И мы устанавливаем атрибут данных – на основе имени и значения – на нашем элементе.
Теперь нам нужно зарегистрировать нашу директиву, чтобы мы могли его использовать. Мы можем сделать это глобально, но, в нашем случае, мы только зарегистрируем его на месте – прямо в нашем Рейтинг.Вью
составная часть.
Наша директива теперь доступна под v-test
название. Попробуйте установить следующую директиву на счетчике:
{{ stars }} of {{ maxStars }}
Теперь проверьте HTML в вашем браузере с помощью инструментов разработчика. Ваш счетчик должен выглядеть так:
2 of 5
Отлично, это работает! Теперь нам не нужны это либо в режиме Dev, ни при создании проекта. Единственная цель этого атрибута данных должна иметь возможность целевым элементам во время тестов, поэтому мы хотим только настроить его, когда мы запустим их. Для этого мы можем использовать Node_env
Переменная среды, предоставляемая WebPack, модуль Bundler Pharing наш проект.
Когда мы запускаем тесты, Node_env
установлен на «Тест»
Отказ Следовательно, мы можем использовать его, чтобы определить, когда установить тестовые атрибуты или нет.
export default (el, binding) => { if (process.env.NODE_ENV === 'test') { Object.keys(binding.value).forEach(value => { el.setAttribute(`data-test-${value}`, binding.value[value]) }) }}
Обновите свое приложение в браузере и снова проверьте счетчик: Атрибут данных ушел Отказ
Теперь мы можем использовать v-test
Директива для всех элементов, которые нам нужны для цели. Давайте возьмем наше тест с ранее:
it('adds `active` class on an inactive star when the user clicks it', () => { const fourthStar = wrapper.findAll('[data-test-id="star"]').at(3) fourthStar.trigger('click') expect(fourthStar.classes()).toContain('active')})
Мы заменили .star
Селектор с [Data-test-id = "star"]
, что позволяет нам изменить классы для целей презентации без разбитых испытаний. Мы получаем одну из преимуществ Односсионный принцип и свободно муфта - Когда ваши абстракции имеют только одну причину для изменения, вы избегаете всех видов надоенных побочных эффектов.
Должны ли мы также использовать эти крючки для классов, которые мы тестируем?
После установки этой директивы к элементам целевых элементов вам может быть задается вопросом, если вы также должны использовать их для замены классов, которые мы активно ищем. Давайте посмотрим на утверждение из нашего первого теста:
expect(wrapper.findAll('.active').length).toEqual(3)
Мы должны использовать v-test
на элементах с Активный
Класс и замените селектор в утверждении? Отличный вопрос Отказ
Агрегаты - это все о тестировании одной вещи одновременно. Первый аргумент Это
Функция - это строка, с которой мы опишем, что мы делаем от перспективы потребителей Отказ
Тест, который оборачивает наше утверждение, говорит Оказывает список звезд с классом, действующим равным op.grade.
Это то, что ожидает потребителя. Когда они передают номер для класс
Собственность, они ожидают получить Равное число активных или выбранных звезд. Тем не менее, в логике нашего компонента Активный
Класс именно то, что мы используем для определения этой черты. Мы назначаем это в зависимости от конкретного состояния, поэтому мы можем визуально различать активные звезды от других. Здесь наличие этого конкретного класса именно то, что мы хотим проверить.
Итак, при принятии решения о том, следует ли использовать селектор, у вас уже есть или установили v-test
Директива, задайте себе вопрос: Что я проверяю, и использует этот селектор, имеет смысл для бизнес-логики?
Как это отличается от функциональных или концевых испытаний?
Сначала это может выглядеть странно для модульных тестовых компонентов. ПОЧЕМУ ВЫ БУДЕТЕ УСТАНОВИТЬ УСТАНОВИТЬ УИ ИЗБОРЫ? Разве это не то, какие функциональные тесты здесь для?
Существует фундаментальная, но тонкая разница, чтобы сделать между тестированием общественного API компонента - aka из Потребитель Перспектива - и тестирование компонента из Пользователь перспектива. Во-первых, давайте подчеркнем что-то важное: Мы тестируем четко определенные функции JavaScript, а не кусочки UI Отказ
Когда вы посмотрите на одно файловый компонент, легко забыть компонент компилирования в функцию JavaScript. Мы не тестируем базовый механизм Vue, который из этой функции вызывает ui-ориентированные побочные эффекты, такие как впрыскивая HTML в доме. Это то, о чем собственный тесты Vue уже заботятся о. В нашем случае наш компонент не отличается от любой другой функции: Он принимает вход и возвращает вывод Отказ Эти причины и последствия являются то, что мы тестируем, и больше ничего.
Что сбивает с толку то, что наши тесты выглядят немного отличаются от обычных модулей. Обычно мы пишем вещи, как:
expect(add(3)(4)).toEqual(7)
Здесь нет дебатов. Ввод и вывод данных, это все, о чем мы заботимся о. С компонентами мы ожидаем, что что-то оказывало визуально. Мы пересекаем виртуальный дом и тестирование на наличие узлов. Это также то, что вы делаете с функциональными или концевыми тестами, с такими инструментами, как Селен или Cypress.io Отказ Так как это отличается?
Вам не нужно путать что Мы делаем, чтобы получить данные, которые мы хотим проверить, а фактические цель теста. С помощью модульных испытаний мы тестируем изолированное поведение. С функциональными или сквозными тестами, мы тестируем сценарии Отказ
Агрегатный тест гарантирует, что единица программы ведет себя как ожидалось. Это обращается к Потребитель компонента - программист, который использует компонент в своем программном обеспечении. Функциональный тест обеспечивает особенность или рабочий процесс ведет себя как ожидалось, от Пользователь Перспектива - последний пользователь, который потребляет полное программное обеспечение.
Идти дальше
Я не буду учиться в деталях каждого теста, потому что все они разделяют аналогичную структуру. Вы можете найти Полный файл SPEC на GitHub И я настоятельно рекомендую вам сначала попытаться реализовать их. Тестирование программного обеспечения - это арт, так как это является наукой, и требует в два раза больше практики, поскольку она требует теории.
Не волнуйтесь, если вы не получили все, или если вы боретесь с написанием ваших первых испытаний: Тестирование печально сложно Отказ Кроме того, если у вас есть вопрос, не стесняйтесь ударить меня на Twitter !
Первоначально опубликовано в FrontStuff.io Отказ