Учебник по модульному тестированию Vue 2 🔧

Решение самых распространенных проблем тестирования любого приложения Vue

Ресурсов для тестирования Vue на удивление мало, несмотря на его быстро растущую популярность. Эта статья проведет вас через процесс создания и тестирования небольшого приложения Vue 2 с помощью Jasmine. Почему жасмин? Это быстро, и сам Vue протестирован с Жасмин. Предпочитаете другую структуру? Без проблем. Практически все здесь по-прежнему применимо.

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

Фон

Моя команда в Morningstar была одним из первых пользователей Vue 1.x в прошлом году. Мы быстро полюбили то, насколько быстро и легко этому учиться. С тех пор мы перешли (на удивление безболезненно!) На Vue 2.x, который предлагает множество замечательных новых функций, в том числе некоторых помощников по тестированию, которые мы увидим позже.

Создание вашей среды

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

Убедитесь, что вы используете узел 6 или выше, и создайте новый проект, используя шаблон веб-пакета интерфейса командной строки. Vue CLI поставляется с Mocha из коробки, но мы заменим его на Jasmine и изменим другие сгенерированные файлы. Варианты, которые я выбрал из подсказки, приведены ниже.

Как вариант, вы можете скачать уже сделанный проект на github здесь и следить за ним.

Приложение для тестирования

Мы будем использовать сторонний API для сбора и отображения статистики качества жизни по городам.

Компонент поиска

Начнем с создания нашего компонента Поиск, чтобы мы могли запрашивать API телепорта, который предоставляет бесплатные данные о качестве жизни.

Документация Teleport API

Установите axios, чтобы мы могли получить доступ к API телепорта

npm i --save axios

Теперь перейдите в src / components, и вы заметите, что там уже есть компонент Hello.vue, сгенерированный интерфейсом командной строки. Переименуйте его в Search.vue и добавьте следующее:

Смешивание конечных точек

Создайте в scr / новую папку под названием mixins. Затем создайте внутри новый файл с именем endpoints с расширением .js вместо .vue. Миксин конечных точек будет содержать помощников, связанных с вызовами API. Мы импортировали это в компонент поиска выше.

Компонент статистики

Stat.vue полностью отвечает за представление статистики. Мы создадим оболочку данных под названием StatView, которая затем преобразует и передаст необходимую статистику.

Компонент StatView

Здесь будет отображаться наша статистика в целом. Статистический компонент будет добавлен для каждой статистики из API. Также есть возможность упорядочить их по возрастанию или убыванию.

Компонент приложения

Компонент приложения - это то место, где мы связываем все вместе и управляем нашими данными. Мы втягиваем компонент поиска и обрабатываем события, которые он может генерировать. StatView будет отображать статистику, если мы получим ее от API.

Найдите сгенерированный файл App.vue в src / и замените его на:

Таблица содержания тестирования 📚

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

Тестовая установка

Спецификация конечных точек

Параметры поиска

Характеристики

Спецификация StatView

Спецификация приложения

Настройка тестирования

Конфигурация

Приведенные ниже пакеты предоставляют нам все необходимые инструменты для тестирования.

npm i --save-dev karma-chrome-launcher karma-jasmine jasmine jasmine-promises jasmine-ajax

Теперь давайте настроим нашу конфигурацию кармы в test / unit / karma.conf.js, чтобы использовать эти новые пакеты. Мы устанавливаем наш браузер на Chrome без головы (требуется Chrome 58 или выше), а наш фреймворк на Jasmine. В качестве альтернативы вы можете вернуться к фантому для своего браузера.

const webpackConfig = require('../../build/webpack.test.conf');
module.exports = (config) => {
  config.set({
    browsers: ['ChromeHeadless'],
    frameworks: ['jasmine'],
    reporters: ['spec', 'coverage'],
    files: [
      './index.js',
    ],
    preprocessors: {
      './index.js': ['webpack', 'sourcemap'],
    },
    webpack: webpackConfig,
    webpackMiddleware: {
      noInfo: true,
    },
    coverageReporter: {
      dir: './coverage',
      reporters: [
        { type: 'lcov', subdir: '.' },
        { type: 'text-summary' },
      ],
    },
  });
};

Чтобы использовать Jasmine-promises и Jasmine-ajax в наших тестах, мы добавляем их в начало нашего тестового индекса по адресу test / unit / index.js.

import Vue from 'vue';
// jasmine helpers 
require('jasmine-ajax');
require('jasmine-promises');
Vue.config.productionTip = false;
... 

Структурирование тестового файла

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

describe('Context', () => { 
  describe('Subject', () => {
    describe('Detail', () => {
      it('acceptance criteria', () => {
      });
    });
  });
});

В приведенном выше примере: «Контекст» - это компонент или миксин. «Субъект» - это группа тестов, таких как методы, вычисление, рендеринг, наблюдатели и т. Д. «Детализация» - это конкретная часть объекта, например, один метод, вычисляемое свойство и т. Д. И «критерии приемлемости», будет индивидуальным критерием, который определяет, работает ли метод, например, так, как ожидалось.

Базовая настройка и разборка

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

import Foo form @/components/foo;
describe('Foo.vue', () => {
  let Constructor;
  let vm;
...

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

afterEach(() => {
  vm.$destroy()
  ...
});

В «Тема» или «Подробности» опишите блоки, которые вы хотите выполнить перед каждым тестом. Назначьте конструктору Vue.extend и смонтируйте новый экземпляр, который будет готов в спецификации (ах).

Такая настройка компонентов позволяет нам использовать встроенный помощник Vue под названием «propsData». Подробнее об этом позже.

beforeEach(() => {
  Constructor = Vue.extend(Foo);
  vm = new Constructor().$mount();
  ...
});

Спецификация поиска

В test / unit / spec уже должен быть файл Hello.spec.js, созданный CLI. Переименуйте его в Search.spec.js и настройте пакет.

Плагины Jasmine для ajax и обещания

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

К счастью, у Jasmine есть плагин для этого под названием Jasmine-ajax. Нам нужно установить его перед тестом и удалить после.

Плагин Jasmine ajax имитирует объект xhr браузера и позволяет нам выбирать, какие запросы мы хотим обрабатывать самостоятельно. Мы можем использовать stubRequest, чтобы отслеживать строку или шаблон и немедленно возвращать ответ.

Мы также используем плагин Jasmine-promises для обработки асинхронных вызовов (любых возможных). Плагин автоматически обрабатывает jasmine's done () или done.fail (), что приводит к гораздо более чистым тестам и меньшему количеству ошибок, связанных с разработкой. Мы просто добавляем наши ожидания в .then () нашего асинхронного метода.

Проверка URL-адресов

Давайте проверим, что «getDataForCity» действительно вызывает API с правильным URL. Используя Jasmine-ajax, мы обращаемся к сделанным запросам и получаем информацию о самом последнем.

Перехват событий

Теперь нам нужно проверить, что «getDataForCity» будет генерировать событие после успешного вызова API. Мы можем следить за встроенным методом Vue «$ emit» и проверять, был ли он вызван с правильными параметрами.

Обработка отклонения

Наконец, мы можем проверить, что «getDataForCity» будет генерировать событие после неудачного вызова API. Чтобы подделать отклоненный запрос, мы можем использовать метод «andCallFunction», предоставляемый Jasmine-ajax, чтобы немедленно вернуть отклоненное обещание.

Несмотря на то, что мы возвращаем отклоненное обещание, мы все еще используем then с Jasmine-promises. Вы можете проверить, работает ли это так, как ожидалось, установив ожидание того, что не удастся и подтвердится.

Спецификация конечных точек

Миксины

Для простых миксинов можно держать их очень чистыми. Это просто обычные объекты javascript, поэтому мы можем протестировать их как таковые, обходя все настройки Vue. В приведенном ниже примере я импортирую миксин конечных точек и назначаю его методы переменной для повторного использования.

Спецификация статистики

Как передать реквизит

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

См. Официальную документацию на propsData.

В приведенном выше примере мы устанавливаем свойство «data» для объекта. Теперь мы можем проверить, что «scorePercentage» возвращает ожидаемое значение на основе свойства, переданного компоненту Stat.

Автоматизация ожиданий

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

Спецификация StatView

Проверка данных API

Опора StatView использует данные из API телепорта и ожидает, что они будут структурированы определенным образом. Мы создадим файл под названием api-data.fixture.js в папке под названием fixtures, расположенной по адресу test / unit .

Теперь у нас есть пример данных, возвращаемых API телепорта, и некоторые другие полезные переменные.

Для «orderCategories» мы используем propsData для передачи фиктивных данных api из фикстуры. Затем мы устанавливаем порядок по возрастанию и ожидаем, что первый элемент в массиве будет соответствовать самому низкому показателю в приспособлении.

Мы можем проверить, что порядок убывания работает аналогичным образом.

Спецификация приложения

Тестирование DOM

Как проверить, правильно ли работает условный рендеринг? Vue обновляет DOM в тиках, поэтому для проверки изменений в DOM мы можем использовать встроенный в экземпляр метод «$ nextTick». Поскольку $ nextTick является асинхронным, мы возвращаем его с помощью Jasmine-promises, а затем проверяем, находится ли ожидаемый элемент на странице. Узел оценивается как истина, поэтому мы можем использовать запрос для ожидаемого узла и использовать «!!» чтобы подтвердить его существование.

Мы можем сделать то же самое для проверки сообщения об ошибке.

Вот и все, ребята! 🎉

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

Ресурсы