pytest触发TypeError: decoding to str需字节类对象 传入list如何解决
错误原因
这个报错和你贴的read_csv函数本身核心逻辑无关——该函数在传入合法CSV文件路径、正常触发文件IO的场景下可以正常运行。报错触发的核心原因是pytest场景下传给csv.reader的可迭代对象不是正常的文件句柄,而是嵌套列表结构,90%以上为以下两种情况:
- 单测Mock逻辑错误:写pytest单测时为了不依赖真实文件,常会用
unittest.mock.patch替换builtins.open,但如果直接把提前构造的CSV解析结果(嵌套列表,每个子元素为一行的字段列表)作为open的返回值,此时with open(...)拿到的csvfile就是这个嵌套列表。传给csv.reader后,迭代取到的第一个元素是子列表,而csv.reader默认会尝试把迭代拿到的行内容解码为字符串,要求输入是bytes/str类型,传入list就会抛出你看到的类型错误。 - 传参错误/插件自动注入:参数化时混淆参数,把已经解析完成的CSV列表数据当成文件路径传给
read_csv;或是安装了自动加载CSV测试数据的pytest插件,插件钩子把open(csv路径)的返回值自动替换成了解析后的嵌套列表,最终触发和Mock错误一致的问题。
可行修复方案
1. 修正单测Mock逻辑
不要直接把嵌套列表作为Mock的open返回值,用mock_open构造符合文件对象行为的Mock,返回原始CSV字符串内容即可,示例代码:
from unittest.mock import mock_open, patch import csv def read_csv(filename): test_data = [] with open(filename, newline="") as csvfile: data = csv.reader(csvfile) next(data) for row in data: test_data.append(row) return test_data def test_read_csv(): # 模拟CSV文件的原始文本内容,包含表头+数据行 mock_csv_text = "name,age,gender\n张三,18,男\n李四,20,女" # 构造符合文件行为的mock对象 mock_file = mock_open(read_data=mock_csv_text) with patch("builtins.open", mock_file): test_data = read_csv("test_demo.csv") # 校验返回结果已跳过表头、内容正确 assert test_data == [["张三", "18", "男"], ["李四", "20", "女"]]
2. 排查调用链传参问题
检查所有调用read_csv的位置,确认传入的第一个参数是CSV文件的合法路径(字符串/Path对象),不要把已经解析完成的列表类型数据作为路径传入。推荐在函数开头加简单的参数校验,同时显式指定文件编码,避免传错类型时抛出难以定位的解码错误、以及跨系统运行的编码兼容问题:
import os import csv def read_csv(filename): # 新增参数类型校验 if not isinstance(filename, (str, os.PathLike)): raise TypeError(f"filename需为路径字符串/Path对象,当前传入类型为{type(filename)}") test_data = [] # 显式指定utf-8编码,兼容多系统运行 with open(filename, newline="", encoding="utf-8") as csvfile: data = csv.reader(csvfile) next(data) for row in data: test_data.append(row) return test_data
内容的提问来源于stack exchange,提问作者sun123
相关产品推荐
相关产品推荐

