use*_*332 5 python mocking pytest pyarrow
我在使用模拟补丁时遇到了我认为的常见问题,因为我无法找出正确的补丁。
我有两个问题希望得到帮助。
使用pyarrow
它的一个例子目前让我感到痛苦:
import pyarrow
class HdfsSearch:
def __init__(self):
self.fs = self._connect()
def _connect(self) -> object:
return pyarrow.hdfs.connect(driver="libhdfs")
def search(self, path: str):
return self.fs.ls(path=path)
Run Code Online (Sandbox Code Playgroud)
import pyarrow
import pytest
from mymodule import HdfsSearch
@pytest.fixture()
def hdfs_connection_fixture(mocker):
mocker.patch("pyarrow.hdfs.connect")
yield HdfsSearch()
def test_hdfs_connection(hdfs_connection_fixture):
pyarrow.hdfs.connect.assert_called_once() # <-- succeeds
def test_hdfs_search(hdfs_connection_fixture):
hdfs_connection_fixture.search(".")
pyarrow.hdfs.HadoopFileSystem.ls.assert_called_once() # <-- fails
Run Code Online (Sandbox Code Playgroud)
$ python -m pytest --verbose test_module.py
=========================================================================================================== test session starts ============================================================================================================
platform linux -- Python 3.7.4, pytest-5.0.1, py-1.8.0, pluggy-0.12.0 -- /home/bbaur/miniconda3/envs/dev/bin/python
cachedir: .pytest_cache
rootdir: /home/user1/work/app
plugins: cov-2.7.1, mock-1.10.4
collected 2 items
test_module.py::test_hdfs_connection PASSED [ 50%]
test_module.py::test_hdfs_search FAILED [100%]
================================================================================================================= FAILURES =================================================================================================================
_____________________________________________________________________________________________________________ test_hdfs_search _____________________________________________________________________________________________________________
hdfs_connection_fixture = <mymodule.HdfsSearch object at 0x7fdb4ec2a610>
def test_hdfs_search(hdfs_connection_fixture):
hdfs_connection_fixture.search(".")
> pyarrow.hdfs.HadoopFileSystem.ls.assert_called_once()
E AttributeError: 'function' object has no attribute 'assert_called_once'
test_module.py:16: AttributeError
Run Code Online (Sandbox Code Playgroud)
您不是在 Mock 对象上调用断言,这是正确的断言:
hdfs_connection_fixture.fs.ls.assert_called_once()
解释:
当您访问 Mock 对象中的任何属性时,它将返回另一个 Mock 对象。
由于您打了补丁,"pyarrow.hdfs.connect"
您已经用 Mock 替换了它,我们称其为 Mock A。您的_connect
方法将返回该 Mock A,然后您将其分配给self.fs
。
现在让我们分解search
调用self.fs.ls
.
self.fs
返回您的 Mock A 对象,然后.ls
将返回一个不同的 Mock 对象,我们称其为 Mock B。在此 Mock B 对象中,您正在执行调用传递(path=path)
。
在您的断言中,您试图访问pyarrow.hdfs.HadoopFileSystem
,但从未修补过。您需要对 Mock B 对象进行断言,该对象位于hdfs_connection_fixture.fs.ls
修补什么
如果您将导入更改mymodule.py
为此,from pyarrow.hdfs import connect
您的补丁将停止工作。
这是为什么?
当您修补某些东西时,您正在更改 aname
指向的内容,而不是实际的对象。
您当前的补丁正在修补名称,pyarrow.hdfs.connect
并且在 mymodule 中您使用相同的名称,pyarrow.hdfs.connect
因此一切正常。
但是,如果您使用from pyarrow.hdfs import connect
mymodule 将导入 realpyarrow.hdfs.connect
并为它创建一个名为 的引用mymodule.connect
。
因此,当您调用connect
inside 时,mymodule
您正在访问mymodule.connect
未修补的 name 。
这就是为什么mymodule.connect
在使用 from import 时需要打补丁的原因。
我建议from x import y
在进行此类修补时使用。它使您尝试模拟的内容更加明确,并且补丁将仅限于该模块,这可以防止不可预见的副作用。
来源,Python 文档中的这一节:在哪里打补丁