python - 模拟 ftplib.FTP 用于单元测试 Python 代码

标签 python unit-testing python-mock

我不知道为什么我没有得到这个,但我想在 Python 中使用 mock 来测试我的函数是否正确调用了 ftplib.FTP 中的函数。我已经简化了一切,但仍然没有完全理解它是如何工作的。这是一个简单的例子:

import unittest
import ftplib
from unittest.mock import patch

def download_file(hostname, file_path, file_name):
    ftp = ftplib.FTP(hostname)
    ftp.login()
    ftp.cwd(file_path)

class TestDownloader(unittest.TestCase):

    @patch('ftplib.FTP')
    def test_download_file(self, mock_ftp):
        download_file('ftp.server.local', 'pub/files', 'wanted_file.txt')

        mock_ftp.cwd.assert_called_with('pub/files')

当我运行它时,我得到:

AssertionError: Expected call: cwd('pub/files')
Not called

我知道它一定是在使用模拟对象,因为那是一个伪造的服务器名称,并且在不打补丁的情况下运行时,它会抛出“socket.gaierror”异常。

如何获取函数正在运行的实际对象?长期目标不是在同一文件中使用“download_file”函数,而是从单独的模块文件中调用它。

最佳答案

当您执行 patch(ftplib.FTP) 时,您正在修补 FTP 构造函数。 dowload_file() 使用它来构建 ftp 对象,以便您调用 login( )cmd() 将是 mock_ftp.return_value 而不是 mock_ftp

你的测试代码应该如下:

class TestDownloader(unittest.TestCase):

    @patch('ftplib.FTP', autospec=True)
    def test_download_file(self, mock_ftp_constructor):
        mock_ftp = mock_ftp_constructor.return_value
        download_file('ftp.server.local', 'pub/files', 'wanted_file.txt')
        mock_ftp_constructor.assert_called_with('ftp.server.local')
        self.assertTrue(mock_ftp.login.called)
        mock_ftp.cwd.assert_called_with('pub/files')

我添加了所有检查和 autospec=True 只是因为是 good practice

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

相关文章:

python - 断言对不同模拟对象的调用序列

python - "Mocking where it' s 已定义“在 python 模拟中?

python - 在 python3 中安装第三方模块 - Ubuntu

python - 如何将日期时间转换为正确的格式以使用 pytz 模块

python - Django ReportLab 错误 - 'str' 对象没有属性 'getKeepWithNext'

python - virtualenv python - 将 Pydev 与 Eclipse neon 结合使用

python - 模拟位于 __init__.py 中的方法

javascript - Angular 4 单元测试出现错误 - 失败 : Cannot read property 'map' of undefined

php - 如何从 Laravel 的数据库中重新加载/刷新模型?

unit-testing - 处理 TDD/单元测试疲劳