python - 在单元测试中模拟 FTP

标签 python ftp mocking

假设我想测试这个非常复杂的函数:

def func(hostname, username, password):
    ftp = FTP(hostname, username, password)
    ftp.retrbinary('RETR README', open('README', 'wb').write)

其中一项测试是:

@patch('FTP')
def test_func_happy_path():
    mock_ftp = Mock()
    mock_ftp.retrbinary = Mock()
    MockFTP.return_value = mock_ftp()
    func('localhost', 'fred', 's3Kr3t')
    assert mock_ftp.retrbinary.called

但是,这将创建一个名为 README 的本地文件,我显然不想要它。

有没有办法模拟/修补 open 以便不创建文件?

很明显,作为变通方法,我可以确保将文件写入 temporary directory我可以将其作为参数传递给 func 或在 func 中创建并返回。

请注意,使用装饰器 @patch('__builtin__.open'),会产生以下期望:

self = <Mock name=u'open()' spec='FTP' id='51439824'>, name = 'write'
    def __getattr__(self, name):
        if name in ('_mock_methods', '_mock_unsafe'):
            raise AttributeError(name)
        elif self._mock_methods is not None:
            if name not in self._mock_methods or name in _all_magics:
>               raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'write'

我将回调传递给 ftp.retrbinary 而不是函数调用。

最佳答案

因此,考虑到您不关心打开时会发生什么,您可以直接模拟它以使其停止写入。为此,您可以采用与模拟 FTP 时类似的方法。因此,考虑到这一点,您可以像这样设置测试代码:

import unittest
from mock import patch, Mock
from my_code import func

class SirTestsAlot(unittest.TestCase):

    @patch('my_code.open')
    @patch('my_code.FTP')
    def test_func_happy_path(self, MockFTP, m_open):
        MockFTP.return_value = Mock()
        mock_ftp_obj = MockFTP()

        m_open.return_value = Mock()

        func('localhost', 'fred', 's3Kr3t')

        assert mock_ftp_obj.retrbinary.called
        assert m_open.called
        # To leverage off of the other solution proposed, you can also
        # check assert called with here too
        m_open.assert_called_once_with('README', 'wb')


if __name__ == '__main__':
    unittest.main()

如您所见,我们在这里所做的是模拟我们正在测试的地方。因此,考虑到这一点,我们针对 my_code 模拟了 openFTP

现在在 my_code 中,没有任何改变:

from ftplib import FTP


def func(hostname, username, password):
    ftp = FTP(hostname, username, password)

    ftp.retrbinary('RETR README', open('README', 'wb').write)

运行此测试套件成功返回。

关于python - 在单元测试中模拟 FTP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35654355/

相关文章:

python - 编程语言如何调用用另一种语言编写的代码?

python - 我如何洗牌庄家继承的套牌?

c - C语言从内存上传FTP文件

python - 如何在独立 Spark 集群 (pySpark) 中使用 FTP 上的文件?

java - Apache ftp.retrieveFileStream 返回 null

c# - 如何模拟作为接口(interface)的接口(interface)属性

unit-testing - 何时使用严格模拟?

python - 使用 with 语句时出错

python - 如何使用Plotly绘制多个饼图圆圈?

unit-testing - 模拟 Entity Framework 上下文