Ответ
Хотя оба инструмента используются для подготовки тестового окружения, у них принципиально разные цели:
-
Mock (Мок) — это объект-заглушка, который заменяет (подменяет) реальную зависимость (например, модуль, класс, функцию) для изоляции тестируемого кода. Это позволяет тестировать компонент, не затрагивая его внешние зависимости (API, базу данных, файловую систему).
-
Fixture (Фикстура) — это функция, которая предоставляет данные, объекты или настраивает состояние для тестов. Она используется для подготовки окружения и устранения дублирования кода (принцип DRY — Don't Repeat Yourself).
Сравнение:
| Аспект | Mock | Fixture |
|---|---|---|
| Основная цель | Изоляция кода, имитация поведения | Подготовка данных и состояния, переиспользование кода |
| Что делает? | Подменяет реальный объект | Предоставляет готовый объект или данные |
| Источник | unittest.mock или pytest-mock (обертка mocker) |
Декоратор @pytest.fixture |
| Пример | Заменить обращение к внешнему API на возврат заранее заданного JSON | Создать подключение к тестовой БД или вернуть объект пользователя |
Пример совместного использования
Представим, что у нас есть функция, которая получает данные пользователя из БД и возвращает его возраст.
import pytest
# ФИКСТУРА: предоставляет тестовые данные
@pytest.fixture
def sample_user_data():
"""Эта фикстура просто возвращает словарь с данными."""
return {"id": 1, "name": "Alice", "age": 30}
# Функция, которую мы хотим протестировать
# (предполагается, что db.get_user обращается к реальной БД)
from my_app import logic, db
def test_get_user_age(mocker, sample_user_data):
# МОК: подменяем функцию обращения к БД
# Теперь при вызове db.get_user(1) не будет реального запроса к БД,
# а вернется значение из фикстуры sample_user_data.
mocker.patch('my_app.db.get_user', return_value=sample_user_data)
# Вызываем тестируемую логику
age = logic.get_user_age(1)
# Проверяем, что наша логика правильно извлекла возраст
assert age == 30
В этом примере:
- Фикстура
sample_user_dataподготовила нам тестовые данные. - Мок
mocker.patchизолировал тест от реальной базы данных, заставив функциюdb.get_userвернуть наши данные.
Ответ 18+ 🔞
Давай разберём эту дичь, чтобы наконец перестать путать мок и фикстуру, как последние распиздяи. Это же две разные сущности, ёпта, как хуй и пальто!
Мок (Mock) — это, грубо говоря, подставная шлюха для твоего кода. Её задача — подменить какую-то реальную зависимость (типа вызова к базе данных, внешнему API или файловой системе), чтобы твой тест не пошёл нахуй из-за этих внешних штук. Ты её настраиваешь: «Вот тут верни такой-то JSON», «А тут кинь исключение». Всё контролируешь.
Фикстура (Fixture) — это, блядь, не подмена, а подготовка. Это такая заботливая мамка, которая перед тестом накрывает тебе стол: создаёт тестовые данные, поднимает временную базу, открывает файл — чтобы ты не повторял этот пиздец в каждом тесте. Принцип DRY, ёбана!
Короче, табличка для особо одарённых:
| Что за хуйня? | Mock (Мок) | Fixture (Фикстура) |
|---|---|---|
| Зачем нужна? | Изолировать код, сымитировать поведение | Подготовить данные/состояние, убрать повторения |
| Что делает? | Подменяет реальный объект на свою подставу | Даёт тебе готовый объект или данные |
| Откуда брать? | unittest.mock или pytest-mock (обёртка) |
Декоратор @pytest.fixture |
| Пример из жизни | Заменить запрос к API на свой canned response | Создать объект пользователя для всех тестов |
Пример, где они ебутся вместе
Смотри, есть у нас функция, которая лезет в базу за пользователем и возвращает его возраст. Нам надо её протестировать, но реальную базу не трогать, а то она нам наебнется посреди ночи.
import pytest
# ФИКСТУРА: просто готовит нам данные, как милая девушка
@pytest.fixture
def sample_user_data():
"""Эта фикстура просто возвращает словарь с данными."""
return {"id": 1, "name": "Alice", "age": 30}
# Допустим, у нас есть модуль logic с тестируемой функцией и модуль db для работы с БД
from my_app import logic, db
def test_get_user_age(mocker, sample_user_data):
# МОК: а вот тут начинается подстава! Говорим: "Функция db.get_user, иди нахуй,
# когда тебя вызовут с аргументом 1, верни не то, что в базе, а то, что нам дала фикстура."
mocker.patch('my_app.db.get_user', return_value=sample_user_data)
# Вызываем нашу логику. Она думает, что ходит в базу, а на самом деле её уже наебали.
age = logic.get_user_age(1)
# И проверяем, что она не обосралась и правильно возраст достала.
assert age == 30
Что тут произошло, блядь?
- Фикстура
sample_user_dataнаготовила нам тестовых данных — словарик с Алисой. - Мок
mocker.patchподсунул нашей функции подмену: вместо реального запроса к базе — наши приготовленные данные. Полная изоляция, ебать! - Тест проходит в стерильных условиях, и мы все довольны.
Вот и вся магия. Не путай, а то получишь пизды от коллег на код-ревью.