实现自己的独特Python Mock模块

问题描述 投票:0回答:1

我使用自己独特的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中将其创建为字符串形式的变量,但这没有用。此外,我尝试计算调用方模块的名称,但在每种情况下都会得到非常相似的错误。

NOTE:

  • 不是内置的模拟模块使用选项。
  • 如果实现两个本地函数,则可以正确地重定向引用。
  • 我愿意接受所有可能的解决方案。
python python-3.x unit-testing class mocking
1个回答
0
投票

我设法用__code__魔术方法解决了我的问题。您可以使用__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
© www.soinside.com 2019 - 2024. All rights reserved.