[英]Mock same Python function across different files in a single mock variable
Let's say I have the following python files:假设我有以下 python 文件:
# source.py
def get_one():
return 1
# file1.py
from source import get_one
def func1():
return get_one()
# file2.py
from source import get_one
def func2():
return get_one()
# script.py
from file1 import func1
from file2 import func2
def main(a, b):
count = 0
for _ in range(a):
count += func1()
for _ in range(b):
count += func2()
return count
I know I can mock out get_one()
in main.py
using the following setup:我知道我可以使用以下设置在main.py
中模拟get_one()
:
def test_mock():
with (
patch("file1.get_one") as mock1,
patch("file2.get_one") as mock2,
):
main(2, 3)
assert mock1.call_count + mock2.call_count == 5
However, this gets increasingly verbose and hard to read if get_one()
needs to be mocked out in many files.但是,如果get_one()
需要在许多文件中进行模拟,这将变得越来越冗长且难以阅读。 I would love to be able to mock out all of its locations in a single mock variable.我希望能够在一个模拟变量中模拟出它的所有位置。 Something like:就像是:
# this test fails, I'm just showing what this ideally would look like
def test_mock():
with patch("file1.get_one", "file2.get_one") as mock:
main(2, 3)
assert mock.call_count == 5
Is there anyway to do this or do I need to use multiple mocks?无论如何要这样做还是我需要使用多个模拟?
Note, I know I can't mock where the function is defined, eg patch("source.get_one")
.注意,我知道我不能模拟函数的定义位置,例如patch("source.get_one")
。
A possible workaround: add a level of indirection in source.py
so that get_one
has a dependency that you can patch:一种可能的解决方法:在source.py
中添加一个间接级别,以便get_one
具有可以修补的依赖项:
def get_one():
return _get_one()
def _get_one():
return 1
and now you can do this in your test:现在您可以在测试中执行此操作:
from script import main
from unittest.mock import patch
def test_mock():
with patch("source._get_one") as mock1:
main(2, 3)
assert mock1.call_count == 5
You can write a helper context manager:您可以编写一个辅助上下文管理器:
import contextlib
from unittest.mock import DEFAULT, patch
@contextlib.contextmanager
def patch_same(target, *targets, new=DEFAULT):
with patch(target, new=new) as new:
if targets:
with patch_same(*targets, new=new):
yield new
else:
yield new
Usage:用法:
def test_mock(self):
with patch_same("file1.get_one", "file2.get_one") as mock:
main(2, 3)
assert mock.call_count == 5
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.