#python #python-3.x #mocking #python-unittest
#питон #python-3.x #насмешливый #python-unittest #python #издевательство
Вопрос:
Не могу предоставить много контекста, учитывая сложность, но я надеюсь на некоторые вопросы, заставляющие задуматься, о том, почему это происходит.
Я тестирую процесс, который загружает файлы в базу данных, поэтому я исправляю учетные данные для подключения к базе данных с помощью unittest.mock.patch
, чтобы использовать тестовые, а не производственные учетные данные. У нас есть серия макетов, которые применяются здесь как contextmanager
упрощенная версия:
from contextlib import ExitStack
def context_stack(contexts):
stack = ExitStack()
for context in contexts:
stack.enter_context(context)
return stack
def patch_mocks():
mocks = [
patch('db_config.ReadWrite', db_mocks.ReadWrite),
patch('db_config.ReadWrite', db_mocks.ReadWrite)
]
return context_stack(mocks)
Он используется как таковой (упрощенный):
with patch_mocks():
LoadFiles(file_list)
LoadFiles
будет выполняться итерация по каждому файлу в file_list
и попытка вставить содержимое в базу данных. Базовые методы подключаются к базе данных с помощью db_config.ReadWrite
но, конечно, они исправлены db_mocks.ReadWrite
. Это работает довольно последовательно, за исключением, казалось бы, очень случайного сбоя, когда он пытается вместо этого использовать db_config.ReadWrite
при попытке создать соединение.
Так, например, может быть сотня файлов, и программа успешно исправит большинство из них, но случайным образом прекратит использование исправления на полпути и провалит тест. Какие условия / переменные могут быть причиной того, что этот патч не будет применен? Существует ли ограничение на количество патчей, которые могут быть применены? Следует ли это применять другим способом?
Комментарии:
1. Без возможности воспроизведения я мог бы предложить только использовать pdb. Добавьте точку останова в начале реального
db_config.ReadWrite
и распечатайте стек вызовов, как только она будет достигнута. Затем вы могли бы проанализировать, откуда поступает этот вызов. Может быть, метод вызывается откуда-то еще? Предполагая, что вам нужно исправить правильное пространство имен…
Ответ №1:
Моя первая линия расследования будет включать это предупреждение из документации по .patch ():
целью должна быть строка в форме ‘package.module.className’. Цель импортирована, и указанный объект заменен новым объектом, поэтому цель должна быть импортируемой из среды, из которой вы вызываете patch(). Цель импортируется при выполнении оформленной функции, а не во время оформления.
и это дополнительное объяснение того, где нужно исправлять
Основной принцип заключается в том, что вы исправляете место поиска объекта, которое не обязательно совпадает с местом его определения.
Я бы попытался найти неисправный случай и проверить состояние среды импорта там, чтобы убедиться, что тот же импорт, который вы используете везде, доступен оттуда.
Ответ №2:
Не исправляйте / не редактируйте, вместо этого используйте шаблон репозитория для доступа к базе данных.
Тогда у вас было бы две реализации интерфейса репозитория:
- в памяти: сохраняет все данные в памяти
- использование DB-драйвера / соединителя: фактически выполняется запись в DB