我使用自己独特的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:
我设法用__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