Принцип DRY (Don’t Repeat Yourself) является основным правилом при разработке программного обеспечения, направленным на минимизацию дублирования кода. В контексте тестирования этот принцип играет не менее важную роль. Повторяющийся код в тестах может привести к различным проблемам, включая трудности в поддержке и обновлении тестов. Чтобы сохранить тесты чистыми, удобными и поддерживаемыми, важно следовать принципу DRY при их написании.
Тесты, как и любой другой код, подвержены изменениям и модификациям. Когда в тестах появляется дублирование, это создает потенциальные проблемы:
Enzyme, как популярная библиотека для тестирования компонентов React, предоставляет инструменты для написания удобных и чистых тестов. Чтобы соблюдать принцип DRY, важно использовать возможности Enzyme для сокращения повторяющихся блоков кода.
beforeEach и afterEachЧтобы избежать повторяющегося кода при настройке и очистке
компонентов, можно использовать хуки beforeEach и
afterEach. Они позволяют выполнить подготовку тестов и их
очистку до и после каждого теста, соответственно.
describe('Мои тесты с Enzyme', () => {
let wrapper;
beforeEach(() => {
wrapper = mount(<MyComponent />);
});
afterEach(() => {
wrapper.unmount();
});
it('Тест 1', () => {
expect(wrapper.find('button').text()).toBe('Submit');
});
it('Тест 2', () => {
expect(wrapper.find('input').prop('placeholder')).toBe('Введите имя');
});
});
В данном примере код для монтирования компонента и его размонтирования будет выполняться до и после каждого теста соответственно, что предотвращает необходимость повторять его в каждом тестовом случае.
Для часто используемых операций, таких как обработка событий, создание компонентов или манипуляция состоянием, следует создавать отдельные вспомогательные функции. Это позволит избежать повторений и упростить поддержку тестов.
const simulateClick = (wrapper, selector) => {
wrapper.find(selector).simulate('click');
};
describe('Тестирование кнопки', () => {
let wrapper;
beforeEach(() => {
wrapper = mount(<MyComponent />);
});
it('Тест 1', () => {
simulateClick(wrapper, 'button');
expect(wrapper.state().clicked).toBe(true);
});
it('Тест 2', () => {
simulateClick(wrapper, 'button');
expect(wrapper.find('button').hasClass('active')).toBe(true);
});
});
В этом примере создание функции simulateClick позволяет
избежать повторения кода, связанного с симуляцией клика, в каждом тесте.
Это делает тесты более лаконичными и удобными для чтения.
Enzyme предоставляет несколько утилит для работы с компонентами,
таких как mount, shallow, и
render. Чтобы избежать повторений, можно использовать эти
утилиты в сочетании с общими компонентами, которые будут
тестироваться.
const setup = (props = {}) => {
return mount(<MyComponent {...props} />);
};
describe('Тестирование компонента с props', () => {
it('Тест 1', () => {
const wrapper = setup({ name: 'John' });
expect(wrapper.find('.name').text()).toBe('John');
});
it('Тест 2', () => {
const wrapper = setup({ name: 'Alice' });
expect(wrapper.find('.name').text()).toBe('Alice');
});
});
Здесь функция setup используется для создания компонента
с различными props для каждого теста. Это позволяет
избежать дублирования кода при настройке компонента в каждом тесте.
Для повторяющихся действий, таких как тестирование взаимодействия с внешними сервисами или API, следует использовать мок-объекты (mocks) и шпионы (spies). Эти инструменты позволяют эмулировать поведение зависимостей, не повторяя их создание в каждом тесте.
const mockApiCall = jest.fn();
describe('Тестирование компонента с API вызовом', () => {
it('Тест 1', () => {
mockApiCall.mockResolvedValue({ data: 'response' });
const wrapper = mount(<MyComponent fetchData={mockApiCall} />);
expect(mockApiCall).toHaveBeenCalledTimes(1);
});
it('Тест 2', () => {
mockApiCall.mockResolvedValue({ data: 'response' });
const wrapper = mount(<MyComponent fetchData={mockApiCall} />);
expect(wrapper.state().data).toBe('response');
});
});
Использование моков и шпионов позволяет избежать необходимости каждый раз вручную создавать моки для тестируемых внешних зависимостей. Все повторяющиеся части тестов можно вынести в одну настройку, улучшая поддерживаемость.
Когда несколько тестов используют одни и те же компоненты или логику, можно создавать базовые классы для тестирования, которые будут содержать повторяющиеся части тестов. Это поможет сделать тесты более структурированными и избежать излишнего дублирования.
class BaseComponentTest {
constructor(component) {
this.component = component;
}
mount() {
return mount(this.component);
}
shallow() {
return shallow(this.component);
}
}
describe('Тестирование компонента MyComponent', () => {
let test;
beforeEach(() => {
test = new BaseComponentTest(<MyComponent />);
});
it('Тест 1', () => {
const wrapper = test.mount();
expect(wrapper.find('button')).toHaveLength(1);
});
it('Тест 2', () => {
const wrapper = test.shallow();
expect(wrapper.find('input')).toHaveLength(1);
});
});
Создание базовых классов позволяет вынести повторяющийся код в один класс и использовать его во всех тестах, что значительно сокращает количество дублирующегося кода.
Принцип DRY в тестировании помогает создавать более чистые, поддерживаемые и удобные для понимания тесты. Использование функций, утилит и общих тестовых классов помогает избежать дублирования кода, повышая эффективность работы над проектом и улучшая качество тестирования.