pytest :如何编写 pytest 代码来检测调用的"func",而无需实际执行"func"



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——我们实际上不需要threadingrequestschild_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_functarget模块中指向的内容,而该名称在测试中的代码中没有使用!

这里最简单的修复方法是修补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_targetsdict,我们可以用我们想要的任何函数/mock填充它。

最新更新