Пробный патч Unittest завершается случайным сбоем в цикле

#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