我有一个正在生产的func1()函数,无法修改。它在另一个模块中调用函数function_to_be_mocked()。这需要输入参数。
我还有另一个函数func2(),它调用func1()。
我正在编写单元测试来测试func2(),并尝试模拟function_to_be_mocked(因为这取决于我本地系统上没有(也不应拥有)的某些键)。我唯一可以修改的是test_func2()。
我进行了如下设置(最小示例):
from othermodule import function_to_be_mocked
import pytest
import mock
def func1():
function_to_be_mocked(None)
def func2():
ret = func1()
print (ret)
@mock.patch('othermodule.function_to_be_mocked', return_value = 3)
def test_func2(mocker):
func2()
othermodule.py是:
def function_to_be_mocked(arg1):
if not arg1 == 'foo':
raise ValueError
我的输出:
直接调用func2:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/blah/temp.py", line 9, in func2
ret = func1()
File "/Users/blah/temp.py", line 6, in func1
function_to_be_mocked(None)
File "/Users/blah/othermodule.py", line 3, in function_to_be_mocked
raise ValueError
ValueError
调用test_func2(),我希望它会被嘲笑:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/blah/venv/lib/python2.7/site-packages/mock/mock.py", line 1305, in patched
return func(*args, **keywargs)
File "/Users/blah/temp.py", line 14, in test_func2
func2()
File "/Users/blah/temp.py", line 9, in func2
ret = func1()
File "/Users/blah/temp.py", line 6, in func1
function_to_be_mocked(None)
File "/Users/blah/othermodule.py", line 3, in function_to_be_mocked
raise ValueError
ValueError
因此,该模拟似乎无效。有没有人想到如何实现这一目标?
============在此行下编辑===========
听起来好像我无法做到我想做的(因为实际上我无法修改与功能1或功能2有关的任何内容。我所能控制的只是测试。
那么让我提出以下问题吧,也许比我的眼睛更有经验的眼睛看到前进的方向。
我有一个功能:
def function_to_be_tested(args):
# Some processing steps
# Function call that works locally
function_that_returns_something_1()
# Some logic
# Function call that works locally
function_that_returns_something_2()
# Function that raises an exception when running locally,
# and since I need to test the logic after this function
# (and cannot edit this code here to bypass it) I would
# (naively) like to mock it.
function_I_would_like_to_mock()
# Much more logic that follows this function.
# And this logic needs to be unit tested.
return some_value_based_on_the_logic
测试:
def test_function_to_be_tested():
assert function_to_be_tested(args) == some_expected_value
在function_I_would_like_to_mock()之前,我可以轻松地对任何内容进行单元测试。
但是由于此函数在本地崩溃(并且我无法编辑代码以阻止它在本地崩溃),所以我认为正确的方法是模拟它并强制使用有意义的返回值。这样我就可以对代码路径进行单元测试。
您会提出什么好的建议?
请注意,我唯一可以修改的是测试功能。我什至无法在主要功能中添加装饰器。
答案 0 :(得分:2)
选项A)
您愿意模拟的函数已加载到func1中。因此,您必须将@patch装饰器应用于func1
import pytest
from unittest import mock
@mock.patch('othermodule.function_to_be_mocked', return_value = 3)
def func1(mocker):
from othermodule import function_to_be_mocked
function_to_be_mocked(None)
def func2():
ret = func1()
print (ret)
def test_func2():
func2()
test_func2()
=========编辑==========
选项B)
import pytest
from unittest import mock
def func1():
from othermodule import function_to_be_mocked
function_to_be_mocked(None)
def func2():
ret = func1()
print (ret)
def test_func2():
with mock.patch('othermodule.function_to_be_mocked', return_value = 3) as irrelevant:
func2()
test_func2()
答案 1 :(得分:0)
“ unittest.mock-模拟对象库”官方文档的Where to patch部分对此进行了很清楚的解释:
a.py
-> Defines SomeClass
b.py
-> from a import SomeClass
-> some_function instantiates SomeClass
现在,我们想测试some_function,但是我们想使用patch()模拟出SomeClass。问题在于,当我们导入模块b时(我们将必须执行此操作),它将从模块a导入SomeClass。如果我们使用patch()来模拟a.SomeClass,那么它将对我们的测试没有影响;模块b已经引用了真实的SomeClass,看来我们的修补没有任何作用。
关键是在使用(或查找位置)的地方修补SomeClass。在这种情况下,some_function实际上将在我们将其导入到的模块b中查找SomeClass。修补程序应如下所示:
@patch('b.SomeClass')
所以我认为在您的情况下,修补程序应如下所示:
@patch("module_of_func2.function_to_be_mocked_as_it_is_imported_there", return_value=3)
def test_func2():
...