You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用mock_open按文件名返回不同模拟文件测试Python函数

问题:测试时根据传入open的文件名返回不同模拟文件

原业务代码:

from smart_open import open
import pandas as pd

def do_something(df):
    # 实际业务逻辑,示例为求和
    return df['test'].sum()

def do_something_else(df):
    # 实际业务逻辑,示例为求均值
    return df['test'].mean()

def foo():
    with open('file1.txt', 'r') as f:
        df1 = pd.read_csv(f)
    value1 = do_something(df1)

    with open('file2.txt', 'r') as f:
        df2 = pd.read_csv(f)
    value2 = do_something_else(df2)
    
    return value1, value2

需求:不读取真实文件,通过mock_open根据不同文件名返回对应模拟数据,完成foo函数的测试。


错误原因分析

你之前的测试代码存在两个核心问题:

  1. forward_filename直接将文件名作为read_data传入mock_open,导致模拟文件对象返回的是文件名字符串,而非CSV格式内容,pd.read_csv无法解析。
  2. read_sample_data错误地将文件名作为pd.read_csv的参数处理,但实际pd.read_csv接收的是文件对象,而非文件名。

正确实现方式(推荐)

核心思路:给open的mock设置side_effect,根据传入的文件名返回包含对应CSV内容的模拟文件对象,让pd.read_csv可以正常读取解析。

测试代码:

from unittest.mock import patch, mock_open
import pandas as pd
from your_module import foo  # 替换为foo函数所在的实际模块名

def test_foo():
    # 定义每个文件名对应的CSV格式内容(需与业务代码中read_csv的解析规则匹配)
    file_contents = {
        'file1.txt': 'test\n1\n2\n',
        'file2.txt': 'test\n3\n4\n'
    }

    def mock_open_by_filename(filename, *args, **kwargs):
        # 根据文件名返回对应的模拟文件对象
        return mock_open(read_data=file_contents[filename]).return_value

    # 替换业务模块中的open函数
    with patch('your_module.open', side_effect=mock_open_by_filename):
        value1, value2 = foo()
        
        # 验证结果符合预期
        assert value1 == 3  # 1+2的求和结果
        assert value2 == 3.5  # 3+4的均值结果

另一种思路:直接mock pd.read_csv

如果不想处理文件对象的模拟,可以通过跟踪open的调用记录获取文件名,再让pd.read_csv返回对应DataFrame:

from unittest.mock import patch, call
import pandas as pd
from your_module import foo

def test_foo_alternative():
    # 定义文件名与对应测试DataFrame的映射
    file_data = {
        'file1.txt': pd.DataFrame({'test': [1,2]}),
        'file2.txt': pd.DataFrame({'test': [3,4]})
    }

    # 记录open的调用参数
    open_calls = []
    def track_open(filename, *args, **kwargs):
        open_calls.append(filename)
        # 返回空模拟文件对象,仅用于满足上下文语法要求
        return mock_open().return_value

    def mock_read_csv(*args, **kwargs):
        # 取出最近一次open调用的文件名,返回对应测试数据
        filename = open_calls.pop(0)
        return file_data[filename]

    with patch('your_module.open', side_effect=track_open), \
         patch('your_module.pd.read_csv', side_effect=mock_read_csv):
        value1, value2 = foo()
        
        assert value1 == 3
        assert value2 == 3.5
        # 验证open的调用次数和参数是否正确
        assert your_module.open.call_count == 2
        assert your_module.open.call_args_list == [call('file1.txt', 'r'), call('file2.txt', 'r')]

内容的提问来源于stack exchange,提问作者Lukas Hestermeyer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 18:24:27