[英]Can I mock a function return that is called within another function call in a Python Test?
有没有办法模拟在另一个 function 调用中调用的 function 返回? 例如:
def bar():
return "baz"
def foo():
return bar()
class Tests(unittest.TestCase):
def test_code(self):
# hijack bar() here to return "bat" instead
assert(foo() == "bat")
我试过使用@mock.patch
,但发现它只允许我模拟我正在调用的 function,而不是 function,因为调用不同的 function 而被调用。
通用补丁
unittest.mock.patch
完全按照我的其他答案建议开箱即用。 你可以根据需要添加任意多的@patch
注解,你select的对象将被打上补丁:
from unittest.mock import patch
def bar():
return "baz"
def foo():
return bar()
class Tests(unittest.TestCase):
@patch(__name__ + '.bar', lambda: 'bat')
def test_code(self):
assert(foo() == "bat")
在此配置中,function bar
将在test_code
完成后恢复。 如果您希望将相同的补丁应用到您的 class 中的所有测试用例,请注释整个 class:
@patch(__name__ + '.bar', lambda: 'bat')
class Tests(unittest.TestCase):
def test_code(self):
assert(foo() == "bat")
补丁全局
您还可以在全局命名空间上使用unittest.mock.patch.dict
来获得相同的结果:
class Tests(unittest.TestCase):
@patch.dict(globals(), {'bar': lambda: 'bat'})
def test_code(self):
assert(foo() == "bat")
您可以编写一个上下文管理器来临时换出全局命名空间中的对象:
class Hijack:
def __init__(self, name, replacement, namespace):
self.name = name
self.replacement = replacement
self.namespace = namespace
def __enter__(self):
self.original = self.namespace[self.name]
self.namespace[self.name] = self.replacement
def __exit__(self, *args):
self.namespace[self.name] = self.original
您可以使用被劫持的方法调用您的模拟 function:
def bar():
return "baz"
def bar_mock():
return "bat"
def foo():
return bar()
class Tests(unittest.TestCase):
def test_code(self):
with Hijack('bar', bar_mock, globals()):
assert(foo() == "bat")
这是一种非常通用的方法,可以在单元测试之外使用。 事实上,将其概括为适用于任何可以表示为某种映射的可变 object 非常简单:
class Hijack:
def __init__(self, name, replacement, namespace, getter=None, setter=None):
self.name = name
self.replacement = replacement
self.namespace = namespace
self.getter = type(namespace).__getitem__ if getter is None else getter
self.setter = type(namespace).__setitem__ if setter is None else setter
def __enter__(self):
self.original = self.getter(self.namespace, self.name)
self.setter(self.namespace, self.name, self.replacement)
def __exit__(self, *args):
self.setter(self.namespace, self.name, self.original)
对于类和其他对象,您可以使用getter=getattr
和setter=setattr
。 对于None
优于KeyError
的情况,您可以使用getter=dict.get
等。
此外,您可以使用monkeypatch
monkeypatch fixture 的seattr
方法。 对于第一个 arguments,它接受一个 object 进行修补,或者一个字符串将被解释为带点的导入路径,最后一部分是属性名称:
# foo_module.py
def bar():
return "baz"
def foo():
return bar()
# test_foo.py
from foo_module import foo
def test_foo(monkeypatch):
monkeypatch.setattr('foo_module.bar', lambda: 'bat')
assert foo() == "bat"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.