🧱 Суть
Это универсальный шаблон автотеста для функций с асинхронными зависимостями (API, сервисы, базы данных).
Он строится вокруг 3 этапов:
- ARRANGE → подготовка данных и моков
- ACT → вызов функции
- ASSERT → проверка результата
📦 Проблема
1. Тесты быстро превращаются в хаос
Без структуры сложно понять, где подготовка, где действие, где проверка.
2. Сложно тестировать зависимости
myService.doSomething()Если не мокать – тест становится нестабильным.
3. Дублируется подготовка данных
Каждый тест начинает заново создавать одни и те же объекты.
✅ Решение
Использовать единый шаблон:
- мок зависимостей через
vi.mock - фикстуры для данных
- хелпер для моков
- очистка состояния перед каждым тестом
💻 Код
Мок зависимости:
vi.mock('@/shared/lib/myService', () => ({
myService: {
doSomething: vi.fn(),
},
}));Фейковые данные:
const makeFakeData = (overrides?: Partial<any>) => ({
id: '1',
name: 'Test',
...overrides,
});Мок ответа сервиса:
const mockService = (response: any) => {
vi.mocked(myService.doSomething).mockResolvedValueOnce(response);
};Тесты:
describe('myFunction', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('returns data on success', async () => {
// ARRANGE
const fakeData = makeFakeData();
mockService({ data: fakeData, error: null });
// ACT
const result = await myFunction();
// ASSERT
expect(result).toEqual(fakeData);
});
it('throws error when service fails', async () => {
// ARRANGE
mockService({ data: null, error: new Error('Ошибка') });
// ASSERT + ACT
await expect(myFunction()).rejects.toThrow('Ошибка');
});
it('calls service once', async () => {
// ARRANGE
mockService({ data: makeFakeData(), error: null });
// ACT
await myFunction();
// ASSERT
expect(myService.doSomething).toHaveBeenCalledTimes(1);
});
});🎯 Вывод
- тест = ARRANGE → ACT → ASSERT
- зависимости всегда мокаются
- данные выносятся в фикстуры
- есть единая точка управления моками
- тесты становятся предсказуемыми и читаемыми