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

pytest测试结果不匹配,CSV读写数据疑似损坏问题排查

CSV写入与读取数据不一致的问题分析

问题背景

编写了用于处理CSV文件的CSVFile类,并编写了pytest参数化测试用例,运行测试后发现读取的数据与写入的数据不一致,报错显示读取到的是字符串形式的列表而非预期的列表元素。

CSVFile类代码

import csv
import os

class CSVFile:
    def __init__(self, filename):
        self.filename = filename

    def write_csv_line(self, row, mode):
        for value in row:
            if value == "None":
                value = ""
        writer = csv.writer(open(self.filename, mode))
        writer.writerow(row)

    def read_file(self):
        data = []
        with open(self.filename, mode="r") as csvfile:
            csv_data = csv.reader(csvfile, delimiter=",")
            for row in csv_data:
                data.append(row)
            return data

    def file_exists(self):
        return os.path.exists(self.filename)

    def delete(self):
        if os.path.exists(self.filename):
            os.remove(self.filename)
            return True
        else:
            return False

pytest测试代码

import pytest
from pytest_lazyfixture import lazy_fixture
from your_module import CSVFile  # 替换为实际模块名

@pytest.fixture(scope="function")
def csv_file():
    csv_file = CSVFile("test")
    yield csv_file
    csv_file.delete()

# Test if file is writable and correct data written
# @pytest.mark.skip("WIP")
@pytest.mark.parametrize(
    "file, row, expected",
    [
        (lazy_fixture("csv_file"), [["a", "b", "c"]], [["a", "b", "c"]]),
    ],
)
def test_CSVLineWritable(file, row, expected):
    file.write_csv_line(row, "w")
    data_read = file.read_file()
    assert file.file_exists() is True
    assert data_read == expected

报错信息

file = <process_resources.CSVFile object at 0x108a64af0>, row = [['a', 'b', 'c']], expected = [['a', 'b', 'c']]

    @pytest.mark.parametrize(
        "file, row, expected",
        [
            (lazy_fixture("csv_file"), [["a", "b", "c"]], [["a", "b", "c"]]),
            # (lazy_fixture("csv_file"), [["None", "b", "c"]], [["", "b", "c"]]),
            # (lazy_fixture("csv_file"), [[None, "b", "c"]], [["", "b", "c"]]),
        ],
    )
    def test_CSVLineWritable(file, row, expected):
        file.write_csv_line(row, "w")
        data_read = file.read_file()
        assert file.file_exists() is True
>       assert data_read == expected
E       assert [["['a', 'b', 'c']"]] == [['a', 'b', 'c']]
E         At index 0 diff: ["['a', 'b', 'c']"] != ['a', 'b', 'c']
E         Full diff:
E         - [['a', 'b', 'c']]
E         + [["['a', 'b', 'c']"]]
E         ?  ++               + +

tests/test_process_resources.py:117: AssertionError

问题原因及修复方案

1. 测试用例传入了嵌套列表

测试用例中传入的row参数是嵌套列表[["a", "b", "c"]],而csv.writer.writerow()方法接收的是一维列表(代表一行的所有元素)。当传入嵌套列表时,writerow会把内部的列表["a","b","c"]直接转换成字符串"['a', 'b', 'c']"写入CSV文件,因此读取后得到的就是包含该字符串的列表[["['a', 'b', 'c']"]],与预期不符。

修复测试用例:将row改为一维列表,对应的expected保持二维列表(因为read_file返回的是所有行组成的二维列表):

@pytest.mark.parametrize(
    "file, row, expected",
    [
        (lazy_fixture("csv_file"), ["a", "b", "c"], [["a", "b", "c"]]),
    ],
)

2. write_csv_line方法的循环未实际修改元素

原方法中的循环:

for value in row:
    if value == "None":
        value = ""

只是修改了临时变量value,并没有改变原列表row中的元素,导致遇到值为"None"的元素时无法替换为空字符串。

修复方法:使用列表推导式或索引遍历修改原列表:

# 方式1:列表推导式(推荐)
def write_csv_line(self, row, mode):
    # 替换"None"为空字符串
    processed_row = ["" if value == "None" else value for value in row]
    with open(self.filename, mode, newline='') as f:
        writer = csv.writer(f)
        writer.writerow(processed_row)

# 方式2:索引遍历修改原列表
def write_csv_line(self, row, mode):
    for i in range(len(row)):
        if row[i] == "None":
            row[i] = ""
    with open(self.filename, mode, newline='') as f:
        writer = csv.writer(f)
        writer.writerow(row)

3. 文件未正确关闭(额外优化)

原方法中直接使用open(self.filename, mode)而未用with语句,可能导致文件未及时刷新关闭,引发读取异常。使用with语句可以确保文件自动关闭,避免资源泄漏和数据写入不完整的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 14:30:51