Короткий ответ
Stub возвращает заранее заданные данные без проверки вызовов, mock дополнительно проверяет, как именно его вызывали, а fake — это упрощённая, но рабочая реализация зависимости (например, БД в памяти вместо настоящей).
Как это работает подробнее
Stub используют, когда важно только получить предсказуемый результат от зависимости, не интересуясь деталями вызова или тем, сколько раз его вызвали. Mock добавляет к этому проверку поведения теста — какие методы вызваны, с какими аргументами, сколько раз именно. Fake — это отдельная, часто самописная реализация с реальной, пусть и упрощённой логикой, например словарь вместо таблицы в БД, который действительно хранит и возвращает данные.
Пример кода
testing_example_304.py
class FakeUserRepository:
def __init__(self):
self._users = {}
def save(self, user):
self._users[user.id] = user
def get(self, user_id):
return self._users.get(user_id)
def test_user_service_saves_and_returns_user():
repo = FakeUserRepository() # fake вместо реальной БД
service = UserService(repo)
service.register(User(id=1, name="Ann"))
assert service.get_user(1).name == "Ann"Что использовать на практике
- Практика. В Python чаще всего используют unittest.mock, который фактически совмещает возможности stub и mock в одном объекте — можно и задать возвращаемое значение (return_value), и проверить вызовы. Fake полезен, когда нужна более реалистичная имитация поведения, чем просто фиксированный ответ, например in-memory репозиторий для unit-тестов бизнес-логики.
Подводные камни
- Риск. Путать термины и называть любой тестовый дублер «моком», что затрудняет общение в команде о том, что именно проверяет конкретный тест. Использовать слишком примитивный stub там, где нужна fake-реализация с реальной логикой хранения и выборки данных, из-за чего тест не замечает ошибки в работе с этими данными.