当通过引用它的变量调用方法时,Unittest .called 不起作用
Unittest .called doesn't work when the method is called through a variable that's referencing it
我的代码中有这样的东西:
def submethod_a():
pass
def submethod_b():
pass
_method_registry = {
"a": submethod_a,
"b": submethod_b,
}
def main_method(key):
method_to_use = _method_registry[key]
method_to_use()
然后我的测试中有这样的东西:
from unittest.mock import patch
@patch("submethod_b")
def test_correct_method_and_arguments(mocked_submethod_b):
main_method(key)
assert mocked_submethod_b.called
测试失败。我这样做是为了测试:
def main_method(key):
if key == "a":
submethod_a()
else:
submethod_b()
然后测试成功。
所以,.called
方法在引用中时不起作用?
这是预期的行为吗?我能做什么?
如果我不以任何其他方式解决它,我想我会重构代码并使用 类 和 2 种不同的“子方法”实现,我认为这应该有效。
谢谢。
最初阅读源代码时,它已经将原始 submethod_b
函数存储在变量 _method_registry
中,因此当您在 运行时 [=56] 对其进行修补时=],虽然函数被替换了,但并没有改变这个变量中已经存储的值。为了证明这一点,让我们添加打印件。
main.py
def submethod_a():
pass
def submethod_b():
pass
_method_registry = {
"a": submethod_a,
"b": submethod_b,
}
def main_method(key):
print(_method_registry["b"], "- Stored function")
print(submethod_b, "- Patched function")
test_main.py
from unittest.mock import patch
from main import main_method
def test_no_patch():
main_method("b")
@patch("main.submethod_b")
def test_with_patch(mocked_submethod_b):
main_method("b")
输出
$ pytest -q -rP
================================================================================================= PASSES ==================================================================================================
______________________________________________________________________________________________ test_no_patch ______________________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
<function submethod_b at 0x7fba0fb63ee0> - Stored function
<function submethod_b at 0x7fba0fb63ee0> - Patched function
_____________________________________________________________________________________________ test_with_patch _____________________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
<function submethod_b at 0x7fba0fb63ee0> - Stored function
<MagicMock name='submethod_b' id='140437103934432'> - Patched function
2 passed in 0.04s
如你所见,没有打补丁,这个值和原来的函数是一样的。但是对于补丁,请注意只有实际功能被替换,而不是已经存储的功能。
备选方案
- 将子方法函数放入其自己的文件中。
- 将子方法导入主文件并按原样使用。
- 修补子方法文件。
- 重新加载主文件,以便在重新创建
_method_registry
时使用修补的子方法。
main.py
from submethod import submethod_a, submethod_b # Or: import submethod
_method_registry = {
"a": submethod_a, # Depending on chosen import style, this can be: submethod.submethod_a
"b": submethod_b, # Depending on chosen import style, this can be: submethod.submethod_b
}
def main_method(key):
print(_method_registry["b"], "- Stored function")
print(submethod_b, "- Patched function")
method_to_use = _method_registry[key]
method_to_use()
submethod.py
def submethod_a():
pass
def submethod_b():
pass
test_main.py
from importlib import reload
import sys
from unittest.mock import patch
from main import main_method
@patch("submethod.submethod_b")
def test_with_patch(mocked_submethod_b):
# Now that the patch is in effect and replaced the submethod.submethod_b, reload the main file so that it recreates _method_registry with the patched function
reload(sys.modules['main'])
main_method("b")
assert mocked_submethod_b.called
输出
$ pytest -q -rP
================================================================================================= PASSES ==================================================================================================
_____________________________________________________________________________________________ test_with_patch _____________________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
<MagicMock name='submethod_b' id='140432453077360'> - Stored function
<MagicMock name='submethod_b' id='140432453077360'> - Patched function
1 passed in 0.04s
现在,存储函数和修补函数本身都指向模拟版本。因此,.called
断言现在成功了。
我的代码中有这样的东西:
def submethod_a():
pass
def submethod_b():
pass
_method_registry = {
"a": submethod_a,
"b": submethod_b,
}
def main_method(key):
method_to_use = _method_registry[key]
method_to_use()
然后我的测试中有这样的东西:
from unittest.mock import patch
@patch("submethod_b")
def test_correct_method_and_arguments(mocked_submethod_b):
main_method(key)
assert mocked_submethod_b.called
测试失败。我这样做是为了测试:
def main_method(key):
if key == "a":
submethod_a()
else:
submethod_b()
然后测试成功。
所以,.called
方法在引用中时不起作用?
这是预期的行为吗?我能做什么?
如果我不以任何其他方式解决它,我想我会重构代码并使用 类 和 2 种不同的“子方法”实现,我认为这应该有效。
谢谢。
最初阅读源代码时,它已经将原始 submethod_b
函数存储在变量 _method_registry
中,因此当您在 运行时 [=56] 对其进行修补时=],虽然函数被替换了,但并没有改变这个变量中已经存储的值。为了证明这一点,让我们添加打印件。
main.py
def submethod_a():
pass
def submethod_b():
pass
_method_registry = {
"a": submethod_a,
"b": submethod_b,
}
def main_method(key):
print(_method_registry["b"], "- Stored function")
print(submethod_b, "- Patched function")
test_main.py
from unittest.mock import patch
from main import main_method
def test_no_patch():
main_method("b")
@patch("main.submethod_b")
def test_with_patch(mocked_submethod_b):
main_method("b")
输出
$ pytest -q -rP
================================================================================================= PASSES ==================================================================================================
______________________________________________________________________________________________ test_no_patch ______________________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
<function submethod_b at 0x7fba0fb63ee0> - Stored function
<function submethod_b at 0x7fba0fb63ee0> - Patched function
_____________________________________________________________________________________________ test_with_patch _____________________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
<function submethod_b at 0x7fba0fb63ee0> - Stored function
<MagicMock name='submethod_b' id='140437103934432'> - Patched function
2 passed in 0.04s
如你所见,没有打补丁,这个值和原来的函数是一样的。但是对于补丁,请注意只有实际功能被替换,而不是已经存储的功能。
备选方案
- 将子方法函数放入其自己的文件中。
- 将子方法导入主文件并按原样使用。
- 修补子方法文件。
- 重新加载主文件,以便在重新创建
_method_registry
时使用修补的子方法。
main.py
from submethod import submethod_a, submethod_b # Or: import submethod
_method_registry = {
"a": submethod_a, # Depending on chosen import style, this can be: submethod.submethod_a
"b": submethod_b, # Depending on chosen import style, this can be: submethod.submethod_b
}
def main_method(key):
print(_method_registry["b"], "- Stored function")
print(submethod_b, "- Patched function")
method_to_use = _method_registry[key]
method_to_use()
submethod.py
def submethod_a():
pass
def submethod_b():
pass
test_main.py
from importlib import reload
import sys
from unittest.mock import patch
from main import main_method
@patch("submethod.submethod_b")
def test_with_patch(mocked_submethod_b):
# Now that the patch is in effect and replaced the submethod.submethod_b, reload the main file so that it recreates _method_registry with the patched function
reload(sys.modules['main'])
main_method("b")
assert mocked_submethod_b.called
输出
$ pytest -q -rP
================================================================================================= PASSES ==================================================================================================
_____________________________________________________________________________________________ test_with_patch _____________________________________________________________________________________________
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
<MagicMock name='submethod_b' id='140432453077360'> - Stored function
<MagicMock name='submethod_b' id='140432453077360'> - Patched function
1 passed in 0.04s
现在,存储函数和修补函数本身都指向模拟版本。因此,.called
断言现在成功了。