我有一个像这样模拟外部库的装置,使用 pytest-mock,它是 unittest.mock 的包装器。
# client.py
import Test as TestLibrary
class LibraryName():
def get_client():
return TestLibrary.Library()
# library_service.py
def using_library():
'''
Edited note: Library().attribute behind the scenes is set to
self.attribute = Attribute()
so this may be affecting the mocking
'''
client = LibraryName.get_client()
return client.attribute.method()
# conftest.py
@pytest.fixture
def library_client_mock(mocker):
import Test as TestLibrary
return mocker.patch.object(TestLibrary, 'Library')
# test_library_service.py
def test_library_method(library_client_mock):
result = using_library()
我可以像这样模拟返回值:
def test_library_method(library_client_mock):
library_client_mock.return_value.attribute.return_value.method.return_value = "test"
result = using_library()
assert result == "test"
但我不能用 side_effect 来模拟抛出异常
def test_library_method(library_client_mock):
library_client_mock.return_value.attribute.return_value.method.side_effect = TypeError # doesn't work
library_client_mock.return_value.attribute.return_value.method.side_effect = TypeError() # doesn't work
attrs = { 'attribute.method.side_effect': TypeError }
library_client_mock.configure_mock(**attrs) # doesn't work
with pytest.raises(TypeError):
using_library() # fails assertion
我在这里缺少什么?
最佳答案
这些是您的代码中的错误:
更改:
library_client_mock.return_value.attribute.return_value.method.return_value = "test"
致:
library_client_mock.return_value.attribute.method.return_value = "test"
更改:
library_client_mock.return_value.attribute.return_value.method.side_effect = TypeError
致:
library_client_mock.return_value.attribute.method.side_effect = TypeError
说明
.return_value
只能用于可调用对象,例如函数为 documented :
return_value
Set this to configure the value returned by calling the mock:
>>> mock = Mock() >>> mock.return_value = 'fish' >>> mock() 'fish'
因此,您只能将 .return_value
用于以下用途:
TestLibrary.Library()
TestLibrary.Library().attribute.method()
但不适用于:
TestLibrary.Library().attribute
因为 .attribute
不是可调用的,例如TestLibrary.Library().attribute()
。
警告
修补Library
的方式是通过其位于Test.Library
(或别名为TestLibrary.Library
)的源位置。具体通过:
import Test as TestLibrary
return mocker.patch.object(TestLibrary, 'Library')
它目前有效,因为您导入和使用它的方式是通过根路径。
# client.py
import Test as TestLibrary
...
return TestLibrary.Library()
...
但是如果我们改变导入该库的方式并将本地版本导入到client.py:
# client.py
from Test import Library # Instead of <import Test as TestLibrary>
...
return Library() # Instead of <TestLibrary.Library()>
...
它现在会失败。理想情况下,您应该 patch the specific name that is used by the system under test ,这里是 client.Library
。
import client
return mocker.patch.object(client, 'Library')
除非您确定将使用该库的所有文件将仅导入根版本而不是本地版本。
关于python - Pytest - 模拟模拟的嵌套属性函数/方法的副作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69196926/