pytest:如何编写pytest代码来检测"func";被调用而不实际执行";func",
target.py:
import requests
import threading
CFG=None
targets={}
def add_target(func):
targets[func.__name__] = func
return func
def parent_func(url):
for funct in set(targets):
threading.Thread(target=targets[funct], args=(CFG[url],)).start()
@add_target
def child_func(url):
try:
response = requests.request("POST", url,
headers={"Content-Type": "application/json"},
data="{"text": "target py test"}")
response.raise_for_status()
except Exception as err:
raise RuntimeError(err)
test_target.py:
在测试过程中,我希望调用child_func((,但不应该执行child_func((主体。相反,在运行测试之后,child_func((会被执行&测试运行结果为";断言错误:False不为真";
from unittest.mock import Mock, patch
import target
# Third-party imports...
from nose.tools import assert_true, assert_is_not_none
target.CFG={'url':"some valid url"}
@patch('target.child_func')
def test_child_func(mock_child_func):
parent_func("url")
assert_true(mock_child_func.called)
首先(为了我自己的理智(,让我们将其缩减为一个实际的MRE——我们实际上不需要threading
或requests
或child_func
的任何实现细节来演示这里的问题。
target.py:
targets={}
def add_target(func):
targets[func.__name__] = func
return func
def parent_func(url):
for func in targets.values():
func(url)
@add_target
def child_func(url):
raise NotImplementedError("The test shouldn't actually call this function!")
test_target.py:
from unittest.mock import Mock, patch
from target import parent_func
@patch('target.child_func')
def test_parent_func(mock_child_func):
parent_func("url")
assert mock_child_func.call_count == 1
在我们的测试中,我们希望parent_func
调用mock_child_func
,而不是真正的child_func
。但当我们运行测试时,我们可以很快发现我们的补丁不起作用:
============================================== short test summary info ===============================================
FAILED test_target.py::test_parent_func - NotImplementedError: The test shouldn't actually call this function!
原因是parent_func
不调用child_func
,而是调用targets['child_func']
。修补'target.child_func'
不会修改实际的函数,它会修改名称child_func
在target
模块中指向的内容,而该名称在测试中的代码中没有使用!
这里最简单的修复方法是修补target.targets
:
from unittest.mock import Mock, patch
from target import parent_func
@patch('target.targets', new_callable=dict)
def test_parent_func(mock_targets):
mock_targets['child_func'] = Mock()
parent_func("url")
assert mock_targets['child_func'].call_count == 1
现在我们的测试通过了,因为当parent_func
遍历其targets
时,它得到了我们的mock_targets
dict,我们可以用我们想要的任何函数/mock填充它。