Это руководство было написано для Vue.js 2 и Vue Test Utils v1.
Версия для Vue.js 3 здесь.
# Тестирование Vuex в компонентах
Исходный код для теста на этой странице можно найти здесь.
# Использование createLocalVue
для тестирования $store.state
В обычном Vue приложении мы устанавливаем Vuex, используя Vue.use(Vuex)
, а затем, передаём новое хранилище Vuex в приложение. Если мы сделаем то же самое в модульном тесте, то все тесты получат Vuex хранилище, даже если оно не используется. vue-test-utils
предоставляет метод createLocalVue
, создающий временный экземпляр Vue
, который можно использовать в тестах. Давайте рассмотрим, как это использовать. Сначала сделаем простой компонент <ComponentWithGetters>
, который отрисовывает имя пользователя, основываясь на состоянии хранилища.
<template>
<div>
<div class="username">
{{ username }}
</div>
</div>
</template>
<script>
export default {
name: "ComponentWithVuex",
data() {
return {
username: this.$store.state.username
}
}
}
</script>
Мы можем использовать createLocalVue
для создания временного экземпляра Vue, в который установим Vuex. Затем, просто передадим новый store
в опции монтирования компонента. Полный тест выглядит так:
import Vuex from "vuex"
import { mount, createLocalVue } from "@vue/test-utils"
import ComponentWithVuex from "@/components/ComponentWithVuex.vue"
const localVue = createLocalVue()
localVue.use(Vuex)
const store = new Vuex.Store({
state: {
username: "Алиса"
}
})
describe("ComponentWithVuex", () => {
it("отрисовывает имя пользователя из настоящего Vuex хранилища", () => {
const wrapper = mount(ComponentWithVuex, {
store,
localVue
})
expect(wrapper.find(".username").text()).toBe("Алиса")
})
})
Тест проходит проверку. Создание нового localVue
вводит некоторый шаблон, из-за чего тест длится дольше.
Если у вас много компонентов, использующих Vuex хранилище, то будет лучше использовать mocks
опцию монтирования и просто замокать хранилище.
# Использование замоканного хранилища
Используя опцию монтирования mocks
, вы можете замокать глобальный объект $store
. Это значит, что вам не нужно применять createLocalVue
или создавать новое Vuex хранилище. Используя эту технику, тест выше можно переписать так:
it("отрисовывает имя пользователя, используя замоканное хранилище", () => {
const wrapper = mount(ComponentWithVuex, {
mocks: {
$store: {
state: { username: "Алиса" }
}
}
})
expect(wrapper.find(".username").text()).toBe("Алиса")
})
Я предпочитаю такой подход. Все необходимые данные объявляются внутри теста и он становится более компактным. Обе техники полезны, и ни одна из них не лучше и не хуже, чем другая.
# Тестирование getters
Используя вышеупомянутые техники, getters
достаточно просто тестировать. Сначала сделаем компонент для теста:
<template>
<div class="fullname">
{{ fullname }}
</div>
</template>
<script>
export default {
name: "ComponentWithGetters",
computed: {
fullname() {
return this.$store.getters.fullname
}
}
}
</script>
Мы хотим проверить, что компонент правильно отрисовывает fullname
пользователя. Для этого теста нам не важно откуда приходит fullname
: важно только то – правильно ли оно отрисуется.
Сначала, используя настоящее Vuex хранилище и createLocalVue
, тест будет выглядеть так:
const localVue = createLocalVue()
localVue.use(Vuex)
const store = new Vuex.Store({
state: {
firstName: "Алиса",
lastName: "До"
},
getters: {
fullname: (state) => state.firstName + " " + state.lastName
}
})
it("отрисовывает имя пользователя, используя настоящий геттер Vuex", () => {
const wrapper = mount(ComponentWithGetters, { store, localVue })
expect(wrapper.find(".fullname").text()).toBe("Алиса До")
})
Тест очень компактный – всего две строчки кода. Тем не менее, здесь много настроек - мы перестраиваем хранилище Vuex. Как альтернативу, можно импортировать настоящее хранилище Vuex с реальным геттером. Это вводит в тест ещё одну зависимость, и при разработке большой системы возможно так, что хранилище Vuex может быть разработано другим программистом и ещё не реализовано.
Давайте посмотрим, как мы можем написать тест, используя опцию монтирования mocks
.
it("отрисовываем имя пользователя, используя вычисленные опции монтирования", () => {
const wrapper = mount(ComponentWithGetters, {
mocks: {
$store: {
getters: {
fullname: "Алиса До"
}
}
}
})
expect(wrapper.find(".fullname").text()).toBe("Алиса До")
})
Теперь вся необходимая информация содержится в тесте. Отлично! Я всегда предпочитаю этот подход, так как тест полностью самостоятельный - в нём есть всё для понимания работы тестируемого компонента.
Мы можем сделать тест ещё короче, используя computed
в опции монтирования.
# Мокаем геттеры, используя computed
Геттеры обычно оборачиваются в computed
свойство.
Помните: этот тест о том, как компонент поведёт себя в зависимости от текущего состояния хранилища. Мы не тестируем реализацию fullname
или работу геттера. Это значит, что мы должны просто заменить настоящее хранилище или замокать его, используя computed
в опции монтирования. Тест можно переписать так:
it("отрисовываем имя пользователя, используя вычисляемое свойство в опции монтирования", () => {
const wrapper = mount(ComponentWithGetters, {
computed: {
fullname: () => "Алиса До"
}
})
expect(wrapper.find(".fullname").text()).toBe("Алиса До")
})
Тест более короткий, чем два предыдущих, но все также выражает намерение компонента.
# Помощники mapState
и mapGetters
Техники, описанные выше, также работают вместе с помощниками mapState
и mapGetters
. Мы можем обновить ComponentWithGetters
вот так:
import { mapGetters } from "vuex"
export default {
name: "ComponentWithGetters",
computed: {
...mapGetters([
'fullname'
])
}
}
Тест все ещё проходит проверку.
# Заключение
В этом руководстве обсудили:
- как использовать
createLocalVue
и настоящее хранилище Vuex для тестирования$store.state
иgetters
- как использовать
mocks
в опциях монтирования, для того, чтобы замокать$store.state
иgetters
- как использовать
computed
в опциях монтирования, чтобы устанавливать желаемое значение для Vuex геттера
Техники для тестирования реализации Vuex геттеров в изоляции можно найти в этом руководстве.
Исходный код для теста на этой странице можно найти здесь.