(十一)用临时文件检查格式往返
1. 从 Python 对象写出,再重新读取
JSON 和 CSV 共用同样的期望值。除了普通标题,再放进逗号、引号与换行,才能检查第五章引入 CSV 读写器的原因:
# 项目文件:quality_project/tests/integration/test_formats.py
# 两种格式分别走真实写入和读取,不靠重复编码逻辑计算期望值。
import pytest
from bookdata.csv_io import read_csv, write_csv
from bookdata.errors import RecordError
from bookdata.json_io import read_json, write_json
from bookdata.models import Book
@pytest.mark.parametrize(
"writer, reader, suffix",
[(write_json, read_json, ".json"), (write_csv, read_csv, ".csv")],
ids=["json", "csv"],
)
def test_roundtrip(tmp_path, writer, reader, suffix):
expected = [Book('Python, "入门"\n手册', True, ["基础", "带,逗号"])]
path = tmp_path / ("books" + suffix)
writer(path, expected)
actual = reader(path)
assert actual == expected
assert actual[0] is not expected[0]
assert actual[0].tags is not expected[0].tags
def test_broken_json_keeps_content(tmp_path):
path = tmp_path / "broken.json"
path.write_text('{"version":', encoding="utf-8")
before = path.read_bytes()
with pytest.raises(RecordError, match="JSON"):
read_json(path)
assert path.read_bytes() == before往返后的值相等,同时 Book 和标签列表都是新对象,检查了“从文件恢复”与“仍引用旧对象”的区别。坏 JSON 则要保留错误并保持文件内容,不能悄悄当成空书目。
2. 检查记录转换的失败反馈
# 项目文件:quality_project/tests/unit/test_records.py
# 用不同错误字段检查反馈,单独核对去空格、去重和记录位置。
import pytest
from bookdata.errors import RecordError
from bookdata.records import book_from_dict, validate_books
@pytest.mark.parametrize(
"record, message",
[
({"title": " "}, "书名"),
({"title": "Python", "finished": "false"}, "布尔值"),
({"title": "Python", "tags": "基础"}, "tags"),
],
)
def test_bad_record(record, message):
with pytest.raises(RecordError, match=message):
book_from_dict(record)
def test_normalize_tags():
book = book_from_dict({"title": " Python ", "tags": ["基础", " 基础 "]})
assert book.title == "Python"
assert book.tags == ["基础"]
def test_duplicate_title_reports_position():
with pytest.raises(RecordError, match="第 2 条记录.*标题重复") as error:
validate_books([{"title": "Python"}, {"title": " Python "}])
assert isinstance(error.value.__cause__, RecordError)期望值直接来自任务:字符串 "false" 不是布尔状态;两个去掉首尾空格后相同的标题是重复记录。测试没有把实现中的判断再抄一遍,而是检查外部可观察的结果与反馈。