Тестирование компонентов Vue должно концентрироваться на поведении и интерфейсе, а не на внутренних деталях реализации. Тесная привязка тестов к внутренней структуре компонентов делает их хрупкими и сложными в поддержке. Изменения в коде, которые не влияют на пользовательский опыт, могут привести к падению тестов, если они ориентированы на детали реализации.
Тесты должны рассматриваться как взаимодействие с компонентом «черного ящика». Основные точки взаимодействия:
Vue Test Utils предоставляет набор инструментов для
работы с компонентами без необходимости обращаться к их внутренним
данным. Основные подходы:
Метод mount и
shallowMount
mount создаёт полный рендер компонента вместе с
дочерними компонентами.shallowMount создаёт поверхностный рендер, заменяя
дочерние компоненты заглушками, что снижает зависимость теста от
внутренних компонентов. Пример:import { shallowMount } from '@vue/test-utils';
import MyComponent from '@/components/MyComponent.vue';
const wrapper = shallowMount(MyComponent, {
props: { title: 'Тест' }
});
expect(wrapper.text()).toContain('Тест');
Здесь тест проверяет поведение компонента через текст, а не через внутренние методы.
Проверка DOM через селекторы и текст Вместо
проверки состояния data или приватных методов, тесты должны
фокусироваться на том, что пользователь видит:
expect(wrapper.find('h1').text()).toBe('Тест');
Такой подход устойчив к внутренним изменениям компонента.
Эмит событий Вместо вызова внутренних методов напрямую, проверяется, что компонент корректно эмитирует события:
wrapper.find('button').trigger('click');
expect(wrapper.emitted()).toHaveProperty('submit');
Это отражает реакцию компонента на действия пользователя.
Изменение состояния компонента через wrapper.setData или
прямую модификацию реактивных переменных привязывает тест к реализации.
Лучше передавать разные значения через пропсы и проверять результат:
await wrapper.setProps({ active: true });
expect(wrapper.classes()).toContain('is-active');
Так тест зависит от того, как компонент реагирует на входные данные, а не от того, какая именно переменная внутри меняется.
Для компонентов, использующих сложные дочерние элементы, стоит
использовать stubs:
const wrapper = shallowMount(ParentComponent, {
stubs: ['ChildComponent']
});
Это позволяет тестировать родительский компонент без зависимости от внутренней реализации дочерних компонентов.
Тестирование деталей реализации (например, приватных методов, внутреннего состояния, порядка вызова функций) делает код тестов ненадежным и сложным в поддержке. Любое изменение внутренней структуры, не влияющее на поведение, приводит к необходимости переписывать тесты. Следование принципу «черного ящика» сохраняет тесты стабильными и отражает реальное поведение приложения.
Любая проверка должна быть оправдана с точки зрения того, что видит и с чем взаимодействует пользователь. Если проверка касается внутреннего состояния без видимого эффекта, вероятнее всего, тест нарушает принцип избегания тестирования деталей реализации.