Отделение логики от UI

В Vue-приложениях отделение бизнес-логики от пользовательского интерфейса является ключевым аспектом для упрощения тестирования и повышения поддерживаемости кода. Vue Test Utils предоставляет инструменты для изоляции компонентов и проверки их поведения без зависимости от конкретного DOM или внешних библиотек.


Компоненты и их обязанности

Компоненты Vue можно разделить на два типа: презентационные и умные (контейнерные).

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

Такое разделение упрощает тестирование:

  1. Презентационные компоненты тестируются с помощью shallow rendering и проверки рендеринга данных.
  2. Умные компоненты тестируются через методы, вычисляемые свойства и обработку событий, без необходимости рендерить сложный DOM.

Использование shallowMount и mount

shallowMount создаёт обёртку компонента без рендеринга дочерних компонентов, что позволяет сосредоточиться на логике текущего компонента:

import { shallowMount } from '@vue/test-utils';
import UserProfile from '@/components/UserProfile.vue';

test('проверка рендеринга имени пользователя', () => {
  const wrapper = shallowMount(UserProfile, {
    props: { name: 'Иван' }
  });
  expect(wrapper.text()).toContain('Иван');
});

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


Изоляция бизнес-логики

Бизнес-логику можно вынести в методы, вычисляемые свойства или отдельные сервисы, чтобы тесты не зависели от DOM.

Пример вынесенной функции:

// services/userService.js
export function formatUserName(user) {
  return `${user.lastName} ${user.firstName}`;
}

Тестирование такой функции полностью отделено от компонента:

import { formatUserName } from '@/services/userService';

test('корректное форматирование имени пользователя', () => {
  const user = { firstName: 'Иван', lastName: 'Петров' };
  expect(formatUserName(user)).toBe('Петров Иван');
});

Проверка событий и взаимодействий

Vue Test Utils позволяет тестировать эмиты событий, что особенно важно для презентационных компонентов:

const wrapper = shallowMount(ButtonComponent);
wrapper.trigger('click');

expect(wrapper.emitted()).toHaveProperty('click');

Эти тесты проверяют только поведение компонента без привязки к сложному DOM или внешним зависимостям.


Моки и стабы для зависимостей

Изоляция логики достигается с помощью моков и стабов. Например, если компонент обращается к Vuex или API, можно заменить реальные зависимости фиктивными:

const $store = {
  state: { count: 5 },
  commit: jest.fn()
};

const wrapper = shallowMount(Counter, {
  global: { mocks: { $store } }
});

wrapper.find('button').trigger('click');
expect($store.commit).toHaveBeenCalledWith('increment');

Это позволяет проверить реакцию компонента на изменения состояния без реальной интеграции с Vuex.


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

Вычисляемые свойства и методы должны быть протестированы отдельно от DOM:

const wrapper = shallowMount(UserProfile, {
  props: { firstName: 'Иван', lastName: 'Петров' }
});

expect(wrapper.vm.fullName).toBe('Иван Петров');
wrapper.vm.updateName('Алексей');
expect(wrapper.vm.fullName).toBe('Алексей Петров');

Такой подход делает тесты быстрыми и надёжными, так как они не зависят от рендера и стилей.


Комбинирование подходов

Эффективное тестирование Vue-компонентов достигается комбинированием:

  • shallowMount для презентационных компонентов
  • моков для внешних зависимостей
  • отдельных тестов для бизнес-логики
  • проверки эмитов и вычисляемых свойств

Это создаёт чистую архитектуру тестов: каждый тест фокусируется на одной ответственности, упрощая поддержку и обнаружение ошибок.


Отделение логики от UI не только ускоряет тестирование, но и повышает повторное использование компонентов, делая код более модульным и предсказуемым.