Самый распространенный вопрос о модульном тестировании компонентов Vue: «Что именно я должен тестировать?»
Хотя можно перетестировать или недотестировать, я наблюдаю, что разработчики часто перетестируют. В конце концов, никто не хочет, чтобы их компоненты давали сбой в производстве без их тестирования.
В этой статье я делюсь некоторыми руководящими принципами для тестирования компонентов, чтобы гарантировать, что эти руководящие принципы не могут проводить много времени на написание тестов, но могут предоставить достаточно охвата, чтобы избежать ошибок.
В этой статье предполагается, что вы уже знакомы с Jest и Vue Test Utils.
Пример компонента
Прежде чем мы изучим эти рекомендации, давайте ознакомимся с примером компонента, который нужно протестировать. компонент с именемItem.vue, — это запись продукта в приложении электронной коммерции.
Ниже приведен исходный код компонента. Обратите внимание, что есть три зависимости: Vuex ($store
), Vue Router ($router
) и Vue Auth ($auth
).
Item.vue
<template>
<div>
<h2>{{ item.title }}</h2>
<button @click="addToCart">Add To Cart</button>
<img :src="item.image"/>
</div>
</template>
<script>
export default {
name: "Item",
props: [ "id" ],
computed: {
item () {
return this.$store.state.find(
item => item.id === this.id
);
}
},
methods: {
addToCart () {
if (this.$auth.check()) {
this.$store.commit("ADD_TO_CART", this.id);
} else {
this.$router.push({ name: "login" });
}
}
}
};
</script>
Настроить файл спецификации
Ниже приведен файл спецификации для тестирования. Среди них мы будем использовать Vue Test Utils для «поверхностного монтирования» примера компонента, таким образом добавляя соответствующие модули и компонент Item, который мы хотим протестировать.
В то же время фабричная функция написана для создания переопределяемого объекта конфигурации, чтобы избежать необходимости указывать три зависимости props и mock в каждом тесте.item.spec.js
import { shallowMount } from "@vue/test-utils";
import Item from "@/components/Item";
function createConfig (overrides) {
const id = 1;
const mocks = {
// Vue Auth
$auth: {
check: () => false
},
// Vue Router
$router: {
push: () => {}
},
// Vuex
$store: {
state: [ { id } ],
commit: () => {}
}
};
const propsData = { id };
return Object.assign({ mocks, propsData }, overrides);
}
describe("Item.vue", () => {
// Tests go here
});
Определить бизнес-логику
Первый и самый важный вопрос, который нужно задать о тестируемом компоненте, — это «что такое бизнес-логика», т. е. что делает компонент?
за этоItem.vue, бизнес-логика такова:
- Согласно полученному
id
информация о записи отображения атрибута - Если пользователь является гостем, нажмитеAdd to Cartкнопка перенаправит на страницу входа
- Если пользователь вошел в систему, нажмитеAdd to CartКнопка вызовет мутацию Vuex.
ADD_TO_CART
.
Определить вход и выход
Когда вы выполняете модульное тестирование компонента, думайте о нем как о черном ящике. Внутренняя логика, такая как методы, вычисляемые свойства и т. д., влияет только на вывод.
Следовательно, следующее внимание уделяется определению входных и выходных данных компонента, поскольку они также являются входными и выходными данными теста.
Входные данные для Item.vue:
-
id
Атрибуты - Состояние данных из Vuex и Vue Auth
- Пользователь нажимает кнопку
Результат:
- Визуализированный HTML
- Данные, отправленные в мутацию Vuex или push-уведомление Vue Router
Некоторые компоненты также принимают формы и события в качестве входных данных и инициируют события в качестве выходных данных.
Тест 1: посетитель нажимает кнопку, чтобы перейти к маршруту
Существует бизнес-логика, которая заключается в том, что «если пользователь является посетителем, нажмитеAdd to CartКнопка перенаправит на страницу входа». Давайте напишем этот тест.
Пишем тесты по компоненту "shallow mount", потом находим и нажимаемAdd to Cartкнопка.
test("router called when guest clicks button", () => {
const config = createConfig();
const wrapper = shallowMount(Item, config);
wrapper
.find("button")
.trigger("click");
// Assertion goes here
}
Мы добавим утверждения позже.
Не выходите за границы входа и выхода
Простой способ сделать это в этом тесте — определить, переходит ли маршрут на страницу входа после нажатия кнопки, например:
import router from "router";
test("router called when guest clicks button", () => {
...
// 错!
const route = router.find(route => route.name === "login");
expect(wrapper.vm.$route.path).toBe(route.path);
}
Хотя это также проверяет выходные данные компонента, оно зависит от функциональности маршрутизации, которая не должна беспокоить компонент.
Было бы лучше протестировать вывод компонента напрямую, то есть вызвать$router.push
. Что касается того, завершена ли наконец маршрутизация, это выходит за рамки данного теста.
Таким образом, мы можем контролировать маршрутpush
метод и утверждает, был ли он вызван объектом маршрута входа в систему.
import router from "router";
test("router called when guest clicks button", () => {
...
jest.spyOn(config.mocks.$router, "push");
const route = router.find(route => route.name === "login");
expect(spy).toHaveBeenCalledWith(route);
}
Тест 2: вызовите vuex после того, как вошедший в систему пользователь нажмет кнопку
Далее давайте проверим бизнес-логику «если пользователь вошел в систему, нажмитеAdd to CartКнопка вызовет мутацию Vuex.ADD_TO_CART
".
Опять же, вам не нужно сообщать, изменилось ли состояние Vuex. Чтобы убедиться в этом, требуется дополнительный отдельный тест хранилища Vuex.
Компонент отвечает только за выполнение коммита, поэтому нам просто нужно протестировать это действие.
сначала перепиши$auth.check
поддельные данные, чтобы заставить его вернутьсяtrue
(Имитация вошедшего в систему пользователя). Затем следите за магазиномcommit
Способ и утверждать кнопку Щелкнуть, чтобы быть вызвана.
test("vuex called when auth user clicks button", () => {
const config = createConfig({
mocks: {
$auth: {
check: () => true
}
}
});
const spy = jest.spyOn(config.mocks.$store, "commit");
const wrapper = shallowMount(Item, config);
wrapper
.find("button")
.trigger("click");
expect(spy).toHaveBeenCalled();
}
Не тестируйте функциональность других библиотек
Компонент Item отображает данные об элементе, особенно заголовок и изображение. Может быть, мы должны написать тест, чтобы проверить это специально? Например:
test("renders correctly", () => {
const wrapper = shallowMount(Item, createConfig());
// Wrong
expect(wrapper.find("h2").text()).toBe(item.title);
}
Это снова ненужный тест, потому что он просто проверяет способность Vue извлекать данные из Vuex и вставлять их в шаблон. Библиотека Vue протестировала этот механизм, поэтому вы должны положиться на него.
Тест 3: визуализируйте правильно
Но подождите, если кто-то случайно поставитtitle
переименован вname
А потом забыть обновить выражение интерполяции, как это сделать? Разве вам не нужно проверить это?
Верно, но если вы тестируете каждый аспект своего шаблона таким образом, когда это имеет значение?
Лучший способ протестировать HTML — использовать снимки для проверки общего результата рендеринга. Это касается не только интерполяции заголовков, но и изображений, текста кнопок, любых классов и т. д.
test("renders correctly", () => {
const wrapper = shallowMount(Item, createConfig());
expect(wrapper).toMatchSnapshot();
});
Другие моменты, которые не нужно тестировать, следующие:
-
src
Привязано ли свойство к элементу img - Соответствуют ли данные, добавленные в хранилище Vuex, вставленным данным.
- Возвращает ли вычисляемое свойство правильные данные
- Маршрутизатор перенаправляет на правильную страницу?
и так далее.
Суммировать
Я думаю, что для этого компонента достаточно трех простых тестов.
Хорошая идея для модульного тестирования компонентов состоит в том, чтобы предположить, что тестирование не нужно, если оно не доказано.
Вы можете задать себе следующие вопросы:
- Является ли это частью бизнес-логики?
- Это прямой тест входных и выходных компонентов этого?
- Это тестирование вашего собственного кода или 3-го вечеринка?
Давайте весело проведем модульное тестирование!
оригинал:v UE JS-разработчики.com/2019/08/26/…
Перевод: 1024 Станция перевода
Больше галантереи передовых технологий можно найти в общедоступном аккаунте WeChat: 1024 станция перевода.