В экосистеме MUI (Material-UI) при разработке интерфейсов на React часто возникает необходимость изолированного тестирования компонентов без зависимости от внешних API, глобального состояния или сложных контекстов. Для этого используются моки (mocks) и стабы (stubs). Они позволяют создавать предсказуемую среду для компонентов, упрощают юнит-тесты и повышают стабильность кода.
Мок — это объект или функция, полностью имитирующая поведение настоящего элемента, включая контроль за вызовами, аргументами и результатами. Основная цель мока — проверка взаимодействия между компонентами или функциями.
Стаб — это объект или функция, возвращающая заранее определённые данные без внутренней логики. Стабы упрощают работу компонента, предоставляя фиксированные ответы для тестирования.
Пример различия:
// Стаб: возвращает фиксированный результат
const fetchUserStub = () => ({ id: 1, name: 'Alice' });
// Мок: отслеживает вызовы и параметры
const fetchUserMock = jest.fn(() => ({ id: 1, name: 'Alice' }));
fetchUserMock();
expect(fetchUserMock).toHaveBeenCalled();
MUI-компоненты часто полагаются на контексты, темы и внешние обработчики событий. Чтобы тестировать их изолированно, удобно создавать моки для:
ThemeProvider)LocalizationProvider,
SnackbarProvider)axios, fetch)onClick, onChange)import { createTheme, ThemeProvider } from '@mui/material/styles';
import Button from '@mui/material/Button';
const themeMock = createTheme({
palette: {
primary: { main: '#1976d2' },
secondary: { main: '#dc004e' },
},
});
function MockedButton() {
return (
<ThemeProvider theme={themeMock}>
<Button color="primary">Нажми меня</Button>
</ThemeProvider>
);
}
В этом примере themeMock используется для тестирования
компонента Button в конкретной цветовой палитре без
зависимости от глобальной темы приложения.
Компоненты MUI часто используют Dialogs, Autocomplete, Select и другие элементы, которые взаимодействуют с асинхронными источниками данных. Для тестирования их поведения применяются асинхронные моки.
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Autocomplete from '@mui/material/Autocomplete';
import TextField from '@mui/material/TextField';
const fetchOptionsMock = jest.fn(() =>
Promise.resolve([{ label: 'Option 1' }, { label: 'Option 2' }])
);
test('Autocomplete загружает опции', async () => {
render(
<Autocomplete
options={[]}
getOptionLabel={(option) => option.label}
renderInput={(params) => <TextField {...params} label="Выберите опцию" />}
onInputCha nge={async (_, value) => {
const options = await fetchOptionsMock();
// обновление состояния
}}
/>
);
await userEvent.type(screen.getByLabelText(/выберите опцию/i), 'O');
expect(fetchOptionsMock).toHaveBeenCalled();
});
Здесь fetchOptionsMock выступает моком
асинхронной функции, что позволяет тесту работать предсказуемо
и не зависеть от реального API.
Стабы полезны, когда необходимо, чтобы компонент возвращал фиксированные данные без проверки вызовов функций.
const optionsStub = [
{ id: 1, label: 'Option A' },
{ id: 2, label: 'Option B' }
];
<Autocomplete
options={optionsStub}
getOptionLabel={(option) => option.label}
renderInput={(params) => <TextField {...params} label="Выбор" />}
/>
Использование стаба optionsStub позволяет
сосредоточиться на тестировании визуальной части и логики взаимодействия
компонента, не заботясь о динамических данных.
Часто эффективнее использовать сочетание моков и стабов:
Пример для компонента Dialog с кнопкой отправки:
import { Dialog, DialogActions, Button } from '@mui/material';
const onSubmitM ock = jest.fn();
const dataStub = { name: 'Alice', email: 'alice@example.com' };
function MockedDialog() {
return (
<Dialog open>
<DialogActions>
<Button onCl ick={() => onSubmitMock(dataStub)}>Отправить</Button>
</DialogActions>
</Dialog>
);
}
// Тест
userEvent.click(screen.getByText(/отправить/i));
expect(onSubmitMock).toHaveBeenCalledWith(dataStub);
Здесь dataStub гарантирует фиксированный ввод, а
onSubmitMock позволяет проверить вызов функции с нужными
параметрами.
MUI и React-компоненты удобно тестировать через Jest и React Testing Library:
jest.fn() создаёт моки функций.jest.mock() позволяет подменять модули, например
axios или @mui/material компоненты.screen и userEvent из Testing Library
взаимодействуют с DOM, позволяя проверять реакцию компонентов на
действия пользователя.jest.mock('axios', () => ({
get: jest.fn(() => Promise.resolve({ data: [{ id: 1, name: 'Alice' }] }))
}));
Такой подход позволяет полностью изолировать тестируемый компонент от внешних зависимостей.
ThemeProvider,
LocalizationProvider), чтобы компонент рендерился корректно
даже в тестовой среде.jest.fn().mockResolvedValue(), чтобы тесты были стабильными
и быстрыми.