首页 > 解决方案 > 如何在测试文件中从未明确存在的对象上修补深埋的方法?

问题描述

这是我的测试文件的一部分:

@pytest.fixture
def live_sftp():

    sftp = SFTP(HOST, USERNAME, PASSWORD)

    # add some directories and files

    yield sftp

    # Cleanup after test

@pytest.mark.parametrize('kwargs,expected', args_and_expected['get_files'])
@patch('<my_code>.sftp.sftp.paramiko.sftp_client.FTPClient.get')
def test_get_files(mock_get, kwargs, expected, live_sftp):
    results = sorted(live_sftp.get_files(**kwargs))
    assert mock_get.call_count == len(results)
    assert_results_match_expected(expected, results)

我正在测试一个名为get_files最终调用的方法get_file。这是我正在测试的课程的缩写版本:

class SFTP(object):
   
    def __init__(self, host, username, password, port=22, rsa_private_key_file=None):
        # do stuff

    @contextmanager
    def create_connection(self):
        transport = <do stuff to define transport>
        conn = paramiko.SFTPClient.from_transport(transport)
        yield conn
        conn.close()
        transport.close()

    def get_file(self, remote_path, local_path=None, connection=None):

        if not local_path:
            local_path = files.create_temp_file_for_path(remote_path)

        if connection:
            connection.get(remote_path, local_path)
        with self.create_connection() as connection:
            connection.get(remote_path, local_path)

        return local_path

    def get_files(<kwargs>):
        # this is a pseudocode version of get_files
        paths = []
        files = <stuff to generate list of files>
        for file in files:
            paths.append(self.get_file(file))
        return paths

connection此类的一个实例,我不确定我在补丁中是否正确引用了它。这get就是我要修补的。

我的目录结构的缩写版本是:

├── <my_code>
│   ├── __init__.py
│   ├── sftp
│   │   ├── __init__.py
│   │   ├── sftp.py
│   │   └── utilities.py
├── pytest.ini
├── requirements.txt
├── setup.py
├── test
│   ├── __init__.py
│   ├── fixtures.py
│   ├── test_sftp.py

我的测试失败了 ModuleNotFoundError: No module named '<my_code>.sftp.sftp.paramiko'; '<my_code.sftp.sftp' is not a package。那讲得通; '<my_code>.sftp.sftp'不是一个包;这是一个模块。但是我已经阅读了文档和其他几个 Stack Overflow 问题,但我找不到说明我想要做什么的示例;我也不能根据我对基本原则的理解(也许不多)来推断它。

也许令人困惑的问题是测试文件所做的唯一相关导入是from <my-code>.sftp import SFTP. SFTP当类的实例connection被告知创建一个时,它们会产生 a ,并且get除了 through 之外无法访问此方法connection

SFTP在我的测试文件中,夹具产生了一个实例。所以也许我的问题是我只能修补与我的测试文件中的导入对象相关的东西,而我的测试文件中唯一具有该 get 方法的东西在它产生之前不存在。它从不明确存在于测试文件中。有没有办法修补connection.get/paramiko.sftp_client.SFTPClient.get假设这些实体都不存在于测试文件中?

编辑历史:我意识到我对我的测试文件做了一些误导和错误的陈述;我已经纠正了他们。我还删除了一个我正在考虑的建议解决方案,考虑到我之前的误导和错误陈述,它才有意义。在另一个编辑中,为了清楚起见,我在问题中移动了代码。

在进行所有编辑时进一步思考的可能解决方案:在我的夹具中,我明确覆盖create_connection. 它是相同的,只是它在创建之后conn和生成它之前设置conn.get为 Mock。夹具函数必须同时返回sftpconn.get我的测试才能访问它。由于不是每个测试都应该模拟conn.get,我有两个选择:制作两个不同的夹具,或者将夹具变成一个接受do_mock布尔值的函数,并返回一个函数,该函数又会返回(sftp, conn.get)。第二个选项将为每个测试添加一行代码。如果有人能提出比这更简单的建议,我将不胜感激。

标签: pythonunit-testingmockingpytest

解决方案


推荐阅读