Реализовать собственный уникальный модуль Python Mock - PullRequest
0 голосов
/ 10 февраля 2020

Я работаю над собственным уникальным Python Mock модулем. Будет интегрирована большая и сложная система. Этот модуль Mock содержит много функций, но они не работают из-за логической проблемы, поэтому я покажу одну из них в качестве репрезентативного примера.

Следующая часть текущей реализации работает как менеджер контекста и должна изменить ссылку исходного объекта для ссылки на макет объекта.

Файл модуля макета:

class MockContextManager(object):
    def __init__(self, original, mocked=None):
        self.original = original
        self.mocked = mocked
    def __enter__(self):
        # We have to save the original reference of the object and assign
        # the reference of the mocked object to original.
        exec("self.local_original = {}".format(self.original))
        exec("{} = {}".format(self.original, self.mocked))
        return self

    def __exit__(self, exc_type, exc_value, exc_traceback):
        # Assign back to the original reference of the object.
        exec("{} = self.local_original".format(self.original))
        if exc_type is not None:
            traceback.print_exception(exc_type, exc_value, exc_traceback)

Файл использования:

from reference_mock import MockContextManager
from other_test_file import FunctionClass

def functionless_dummy_function(*args, **kwargs):
    return None

class TestClass(object):
    def __init__(self):
        self.function_class_instance = FunctionClass()

    def test_mock_context_manager(self):

        with MockContextManager(
            original="self.function_class_instance.show_info",
            mocked="functionless_dummy_function",
        ):
            # The "functionless_dummy_function" function should be called instead of "show_info" method.
            self.function_class_instance.show_info()

Ошибка при получении:

AttributeError: 'MockContextManager' object has no attribute 'function_class_instance'

Хорошо, я понимаю проблему, но мне нужно использовать self для идентификации моей переменной экземпляра.

Если я хочу перенаправить глобальную переменную, я получаю следующее ошибка:

NameError: name 'my_global_veriable' is not defined

Я попытался передать self в качестве параметра и создать переменную в виде строки в exec, но это не сработало. Кроме того, я попытался вычислить имя модуля вызывающего абонента, но в каждом случае получаю очень похожую ошибку.

ПРИМЕЧАНИЕ:

  • Встроенный макет использование модуля не вариант.
  • Если я реализую 2 локальные функции, я могу правильно перенаправить ссылки.
  • Я открыт для любого возможного решения.

1 Ответ

0 голосов
/ 24 февраля 2020

Мне удалось решить мою проблему с помощью метода __code__ magi c. Вы можете получить с помощью __code__: объект кода, содержащий байт-код скомпилированной функции. На самом деле мой менеджер контекста изменяет скомпилированный код в методах / функциях получения.

Код:

class MockContextManager(object):

    def __init__(
        self,
        original: Any,
        mocked: Any = None,
    ):
        self.original = original
        self.mocked = mocked

    def __enter__(self):

        # We have to save the original reference of the object and assign
        # the reference of the mocked object to original.
        self.prev = getattr(self.original, "__code__")
        self.original.__code__ = getattr(self.mocked, "__code__")
        return self

    def __exit__(self, exc_type, exc_value, exc_traceback):
        # Set back the original reference of the getting object.
        self.original.__code__ = self.prev
        if exc_type is not None:
            traceback.print_exception(exc_type, exc_value, exc_traceback)

Использование:

from my_module import my_function  # "my_function" returns 10  

def my_mocked_function():
    return 5

print(my_function)
with MockContextManager(original=my_function, mocked=my_mocked_function):
    print(my_function)
print(my_function)

Выход:

>>> python3 test.py
10
5
10
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...