Чем журнал mock_calls отличается от method_calls при проверке вызовов вложенного mock?
mock_calls фиксирует все вызовы самого mock, его методов, дочерних mock-объектов и поддерживаемых магических методов. method_calls фиксирует только вызовы методов самого mock и его дочерних объектов, поэтому прямой вызов корневого mock в него не попадёт.
Mock-объекты появились как средство изолировать тестируемый код от внешних зависимостей и проверять не только результат, но и взаимодействие с зависимостью. Для этого библиотекам тестирования понадобился журнал фактических вызовов, включая вызовы методов и цепочки дочерних объектов.
Разделение на mock_calls и method_calls позволяет выбрать подходящую строгость проверки: анализировать весь протокол взаимодействия либо только вызовы методов, не учитывая непосредственный вызов самого объекта.
Неверный выбор журнала может привести к неполному тесту. Если проверять только method_calls, тест не заметит прямой вызов callable-mock, например неожиданный вызов клиента до обращения к его методу.
Обратная проблема тоже возможна: проверка mock_calls может сделать тест слишком хрупким, если в него попадут служебные или магические вызовы, не являющиеся частью существенного контракта.
mock_calls — общий журнал взаимодействий с mock. В него входят вызовы самого объекта, вызовы его методов и вызовы автоматически создаваемых дочерних mock-объектов; цепочка вроде обращения к методу дочернего объекта представляется одной структурированной записью.
method_calls содержит вызовы методов mock и его дочерних объектов, но исключает вызов самого корневого mock. Поэтому при выборе журнала нужно определить, что является контрактом: факт вызова объекта как функции или только вызовы его методов.
Для точечной проверки обычно лучше использовать утверждение на конкретном mock или методе. Для проверки последовательности взаимодействия нескольких дочерних объектов подходит mock_calls, а для анализа только методного интерфейса — method_calls.
Есть важное ограничение цепочек: аргументы вызова родительского mock не сохраняются как часть последующего дочернего вызова. Поэтому проверка записи цепочки не всегда доказывает корректность всех аргументов каждого промежуточного звена; значимые промежуточные вызовы лучше проверять отдельно.
В тесте HTTP-клиент представлен mock-объектом. Разработчик проверял method_calls и обнаружил вызов метода request, но тест не выявил дополнительный прямой вызов самого клиента, который запускал нежелательный повторный запрос.
Первый вариант — проверять только method_calls. Он прост и устойчив к некоторым деталям реализации, но не видит вызовы корневого callable-mock. Второй вариант — проверять весь mock_calls; он обнаруживает неожиданный вызов, но может сильнее связывать тест с порядком и внутренней структурой взаимодействия.
Было выбрано точечное утверждение для обязательного вызова request и отдельная проверка mock_calls для запрета лишнего прямого вызова клиента. Такой вариант сохранил проверку публичного взаимодействия и одновременно выявил регрессию без проверки несущественных деталей.
method_calls?Нет. method_calls предназначен для вызовов методов самого mock и его дочерних объектов. Если объект используется как вызываемый объект, такой вызов будет отражён в mock_calls, но не в method_calls.
mock_calls позволяет полностью проверить аргументы цепочного вызова?Нет. Журнал сохраняет структуру цепочки, но аргументы вызова родительского объекта не становятся частью последующего вызова дочернего объекта. Поэтому проверка последней записи цепочки может не подтвердить корректность аргументов промежуточного звена. Для критичных аргументов следует проверять соответствующий дочерний mock отдельно.
mock_calls может быть хуже проверки конкретного метода?Полный журнал включает больше деталей: порядок обращений, вызовы дочерних mock и магические методы. Изменение внутренней реализации, не меняющее контракт, может тогда сломать тест. Проверка конкретного метода обычно лучше выражает требование, но может пропустить неожиданные дополнительные взаимодействия, поэтому выбор зависит от того, проверяется ли точечный контракт или весь протокол вызовов.