我正在尝试学习如何使用 pytest 和模拟进行单元测试。我有一个非常简单的用例:
from simple_salesforce import Salesforce
from unittest.mock import Mock
class SFClient:
def __init__(self, sf_client: Salesforce):
self._simple_sf_client = sf_client
def bulk2(self, query: str, path: str, max_records: int) -> list[dict]:
return self._simple_sf_client.bulk2.Account.download(
query=query, path=path, max_records=max_records
)
def test_client_bulk2():
mock_sf = Mock()
config = {'bulk2.return_value.Account.return_value.download.return_value': 'test'}
mock_sf.configure_mock(**config)
client = SFClient(sf_client=mock_sf)
assert client.bulk2('query', 'path', 1) == 'test'
assert False
正如你所看到的,我正在尝试模拟对
self._simple_sf_client.bulk2.Account.download
的链式调用,但是 assert client.bulk2('query', 'path', 1) == 'test'
尝试将模拟对象与字符串进行比较总是失败。
$ poetry run pytest
F [100%]
======================================================================================================================================================= FAILURES =======================================================================================================================================================
__________________________________________________________________________________________________________________________________________________ test_client_bulk2 ___________________________________________________________________________________________________________________________________________________
def test_client_bulk2():
mock_sf = Mock()
config = {'bulk2.return_value.Account.return_value.download.return_value': 'test'}
mock_sf.configure_mock(**config)
client = SFClient(sf_client=mock_sf)
> assert client.bulk2('query', 'path', 1) == 'test'
E AssertionError: assert <Mock name='mock.bulk2.Account.download()' id='140589080832208'> == 'test'
E + where <Mock name='mock.bulk2.Account.download()' id='140589080832208'> = <bound method SFClient.bulk2 of <tests.test_salesforce.SFClient object at 0x7fdd73acdd90>>('query', 'path', 1)
E + where <bound method SFClient.bulk2 of <tests.test_salesforce.SFClient object at 0x7fdd73acdd90>> = <tests.test_salesforce.SFClient object at 0x7fdd73acdd90>.bulk2
tests/test_salesforce.py:27: AssertionError
=================================================================================================================================================== warnings summary ===================================================================================================================================================
../../.cache/pypoetry/virtualenvs/salesforce-archivist-n3oqdCBe-py3.11/lib/python3.11/site-packages/zeep/utils.py:1
/home/piotrek/.cache/pypoetry/virtualenvs/salesforce-archivist-n3oqdCBe-py3.11/lib/python3.11/site-packages/zeep/utils.py:1: DeprecationWarning: 'cgi' is deprecated and slated for removal in Python 3.13
import cgi
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=============================================================================================================================================== short test summary info ================================================================================================================================================
FAILED tests/test_salesforce.py::test_client_bulk2 - AssertionError: assert <Mock name='mock.bulk2.Account.download()' id='140589080832208'> == 'test'
1 failed, 1 warning in 0.19s
我一定在这里遗漏了一些明显的东西。为什么它不返回我在配置模拟时设置的值?谢谢
看起来您正确配置了模拟,但问题在于断言中的比较。
assert
语句正在将client.bulk2('query', 'path', 1)
的返回值与字符串“test”进行比较,但返回值是一个模拟对象,而不是字符串“test”。
要解决此问题,您需要访问模拟对象的返回值。在你的例子中,模拟对象代表方法
bulk2.Account.download
。您可以使用模拟的 return_value
属性访问返回值。这是更正的断言:
assert client.bulk2('query', 'path', 1).return_value == 'test'
这会将模拟的返回值(设置为“test”)与字符串“test”进行比较。相应地更新测试函数中的断言,它应该按预期工作。
这是修改后的测试函数:
def test_client_bulk2():
mock_sf = Mock()
config = {'bulk2.return_value.Account.return_value.download.return_value': 'test'}
mock_sf.configure_mock(**config)
client = SFClient(sf_client=mock_sf)
assert client.bulk2('query', 'path', 1).return_value == 'test'
此更改应该可以解决您遇到的 AssertionError。