Зависимость принимает context.Context, но mock всегда возвращает успех. Какой контракт тест перестаёт проверять?
Такой mock перестаёт проверять поведение зависимости при отмене контекста: прекращение операции и возврат ошибки, совместимой с context.Canceled или context.DeadlineExceeded. Если отмена входит в контракт взаимодействия, mock должен воспроизводить её существенный результат, иначе unit-тест может быть зелёным при ошибке в production.
context.Context предназначен для передачи отмены, дедлайнов и ограничений выполнения через границы функций и сервисов. Mock-объекты появились как способ изолировать тестируемый код от реальных сетевых, файловых и других внешних зависимостей.
Изоляция полезна только тогда, когда mock сохраняет значимые свойства контракта. Если он безусловно возвращает успех, тест проверяет лишь обычный сценарий и скрывает ошибки обработки отмены.
Реальная зависимость может завершить запрос при отмене контекста, освободить ресурсы и вернуть ошибку. Mock, который всегда отвечает успешно, не позволяет обнаружить код, продолжающий работу после отмены или неправильно классифицирующий такую ошибку.
Это особенно опасно для HTTP-клиентов, обработчиков очередей и долгих операций. В результате система может выполнять ненужную работу, удерживать ресурсы или выдавать успешный результат для уже отменённого запроса.
Mock должен проверять только те последствия отмены, которые являются частью контракта тестируемого кода. Обычно это возврат ошибки, проверяемой через errors.Is, а не сравнение текста ошибки или конкретного экземпляра.
Минимальный вариант mock может реагировать на закрытие ctx.Done():
Сам факт передачи контекста ещё не гарантирует остановку работы: отмена в Go кооперативная. Реальная зависимость или mock должны проверять сигнал отмены, а вызывающий код — корректно обрабатывать возвращённую ошибку.
Не следует заставлять каждый mock воспроизводить все детали настоящей реализации. Если конкретная функция должна лишь передать контекст дальше, достаточно проверить передачу нужного контекста; если же она обязана реагировать на отмену, нужен сценарий с отменённым контекстом и проверкой результата.
Сервис отправлял запрос во внешний API. В unit-тестах mock всегда возвращал успешный ответ, поэтому ошибка в обработчике отмены не обнаруживалась: после отмены HTTP-запроса сервис продолжал формировать результат.
Рассматривались три варианта. Использование реального API давало реалистичное поведение, но делало тест медленным и нестабильным. Проверка только факта передачи context.Context была дешёвой, но не проверяла реакцию на отмену. Специальный сценарий mock с уже отменённым контекстом проверял нужный контракт без внешней системы.
Выбрали третий вариант, а интеграционную проверку оставили отдельному уровню тестов. В результате unit-тест фиксировал возврат ошибки отмены, а тесты оставались быстрыми и детерминированными.
Нет. Непустой контекст не означает, что его отмена действительно влияет на операцию. Нужно проверять именно требуемое поведение: например, что при отмене операция прекращается и возвращается соответствующая ошибка.
errors.Is?Код может добавить к исходной ошибке контекст через оборачивание. Сравнение указателей или текстов в таком случае становится хрупким, а errors.Is сохраняет проверку смысловой принадлежности ошибки к context.Canceled или context.DeadlineExceeded.
Не всегда. Mock обязан моделировать контракт, а не внутреннюю реализацию зависимости. Если контракт гарантирует остановку операции, mock должен это отражать; если гарантируется только передача контекста, достаточно проверить передачу и отдельно тестировать обработку результата реальной зависимостью на интеграционном уровне.