Когда мóкать, когда не мóкать при unit-тестировании?

Есть функция с кучей зависимостей. Псевдокод:
register_user (login, pass, email) {
    if data_valid (login, pass, email) then
        hash = generate_hash(pass)
        add_to_database(login, hash, email)
        send_email(email)
    else
       return 'invalid data'
}

Что лучше?
  1. стараться мокать всё возможное;
  2. стараться не мокать, насколько это возможно и пытаться создать реальные условия - поднимать фейковую базу, заполнять её, реально создавать хеш, реально отправлять письмо на поднятый сервер


Пожалуйста, обоснуйте ответ.
  • Вопрос задан
  • 409 просмотров
Решения вопроса 3
@vabka
Токсичный
Лучше никогда не мокать, если возможно.
Мокать только в одной из следующих ситуаций:
- Оригинал требует слишком долгого сетапа или работает слишком медленно
- Оригинал зависит от независимых от нас сервисов (api клиент платёжной системы)
- Оригинал сильно зависит от пользовательского ввода
- Оригинал не детерминиcтичен

В некоторых случаях вместо моков можно сделать фейк:
- Вместо реальной БД - объект в оперативной памяти
- Вместо реального SMTP клиента и почтового сервера - почта в памяти

При этом, если это вообще возможно, нужно покрыть тестами и оригинальные функции по работе с бд и почтой, тк это критичный код, но для этого есть интеграционные и end2end тесты

В вашем примере вполне можно замокать отправку на почту, тк это сложно тестировать.
Сохранение в БД можно заменить на фейк, ради более быстрого прохождения теста
Генерацию хеша можно оставить оригинальную.
Ответ написан
zoonman
@zoonman
CEO @ LinuxQuestions.ru
При юнит-тестировании принято тестировать один уровень абстракции.

В вашем случае add_to_database и send_email будут моками, т.к. они представляют собой функции другого уровня абстракции и должны тестироваться отдельным тестом. data_valid и generate_hash являются чистыми функциями, которые не имеют никаких посторонних эффектов и не изменяют внутреннего состояния объектов.

В остальном Василий все правильно написал.
Ответ написан
@chaetal
разработчик ПО и преподаватель
Mock-и нужны в первую очередь в TDD/BDD — чтобы не отвлекаться от реализуемой в данный момент задачи.

При написании модульных (именно модульных!) тестов к уже существующему коду лучше использовать другие виды "дублеров" (test doubles): стабы, фейки и т.д.

Если под "моканьем" понимается замена реальных объектов, с которыми взаимодействует тестируемый (их называют collaborators --- "сотрудники"), дублерами, то да, имеет смысл изолировать функциональность тестируемого модуля от реализации сотрудников — чтобы тест ловил ошибки именно в тестируемой функциональности, а не в зависимостях.

В общем, смысл заключается именно в том, чтобы тестировать именно нужную функциональность, изолируя ее от побочных зависимостей. В идеале, упавший тест должен сразу как можно точнее показывать проблемный код.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы