【问题标题】:pytest How to mock s3fs.S3FileSystem open filepytest 如何模拟 s3fs.S3FileSystem 打开文件
【发布时间】:2020-11-06 21:10:26
【问题描述】:

我正在尝试模拟在 S3 存储桶中打开文件的调用。我的代码是:

# mymodule.py
import s3fs
#...
def __init__(self):
    self.s3_filesystem = s3fs.S3FileSystem(anon=False, key=s3_key,
                                           secret=s3_secret)
#...
def mymethod(self):
    with self.s3_filesystem.open(filename, 'r') as csv_file:
        file_dataframe = pd.read_csv(csv_file)

我在 pytest 中的模拟是:

import pytest

def test(mocker)                                       
    mocker.patch('mypackage.mymodule.s3fs.S3FileSystem.open',
                 return_value=open)

但在运行测试时出现错误:

>       with self.s3_filesystem.open(filename, 'r') as csv_file:
E       AttributeError: __enter__

知道为什么吗?

【问题讨论】:

  • 我通过使用 side_effect=open 找到了解决方案,而不是使用 return_value=open。 mocker.patch('mypackage.mymodule.s3fs.S3FileSystem.open', side_effect=open) 见fgimian.github.io/blog/2014/04/10/…

标签: python mocking pytest python-s3fs


【解决方案1】:

免责声明:我的答案的所有功劳都归功于 OP Juan Fernando Jaramillo Botero 以及他对他自己的问题的评论,上面。我在这里发布了一个答案,因为看起来 OP 目前没有至少 15 个声望点 - 因此,无法回答他自己的问题,如 in this help page 所示。 拜托,如果不是这样,我鼓励 OP 添加他的答案 - 并接受它 - 因为它对我帮助很大!


我遇到了同样的问题,我不得不在 pytest 测试套件中模拟来自 s3fs.S3FileSystem 的两种方法:open(作为 OP)和 ls

通过使用装饰器patch 及其参数side_effect,测试期间对s3fs.S3FileSystem.opens3fs.S3FileSystem.ls 的所有调用分别被openos.listdir 正确替换,在我的情况下是想要的效果。

简化情况:

my_module.py

​​>
import s3fs


class Operation():
    def compile_files(self, fs, input_bucket):
        files = fs.ls(input_bucket)

        return files

    def copy_files(self, fs, files, input_bucket, output_bucket):
        for file in files:
            with fs.open(f'{input_bucket}/{file}', 'rb') as source:
                with fs.open(f'{output_bucket}/{file}', 'wb') as destination:
                    destination.write(source.read())

    def transform(self, input_bucket, output_bucket):
        fs = s3fs.S3FileSystem()

        files = self.compile_files(fs, input_bucket)

        self.copy_files(fs, files, input_bucket, output_bucket)

my_module_test.py

​​>
import os
from unittest.mock import patch

from my_module import Operation


@patch('s3fs.S3FileSystem.open', side_effect=open)
@patch('s3fs.S3FileSystem.ls', side_effect=os.listdir)
def test_my_module(mock_s3fs_ls, mock_s3fs_open):
    input_bucket = 'test/fixtures/files'
    output_bucket = 'test/fixtures/tmp_output'
    os.mkdir(output_bucket)

    Operation().transform(input_bucket, output_bucket)

    # Proceed to assert everything went as expected...

请注意,测试文件不会导入pytest,但它是完全兼容的,可以在pytest 测试套件中运行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-05
    • 1970-01-01
    • 2012-04-20
    • 2023-03-09
    • 1970-01-01
    • 2018-12-12
    • 2022-08-19
    • 1970-01-01
    相关资源
    最近更新 更多