使用pytest校验SQLite数据库创建及CSV导出测试报错排查
问题根因
- 全局共享
Crud_db实例导致测试用例之间状态互相干扰,前一个测试打开的数据库连接未关闭就执行下一个测试,容易触发文件占用EBUSY错误 tmpdir是pytest自动创建的临时文件夹,你没有将数据库、CSV输出路径指向这个临时目录,文件实际生成在项目根目录,尝试直接读取临时文件夹本身(不是目标文件)自然触发PermissionError- 测试逻辑未做资源清理,测试生成的文件残留在工作目录,反复运行容易出现文件锁冲突
正确测试实现
import os import pytest import sqlite3 import pandas as pd from class_helper import Crud_db def test_connect_creates_db_file(tmpdir): # 数据库文件放在临时目录,避免污染项目工作目录 db_path = tmpdir.join("test.db") db = Crud_db(database=str(db_path)) # 连接前确认文件不存在 assert not os.path.exists(db_path) db.connect() # 连接创建后主动关闭,释放文件锁 db.close() # 校验数据库文件成功生成 assert os.path.exists(db_path) # 额外校验生成的是合法sqlite文件 verify_conn = sqlite3.connect(str(db_path)) verify_conn.close() def test_tables(tmpdir): # 每个测试用例单独创建db实例,禁止全局共享实例 db_path = tmpdir.join("test.db") db = Crud_db(database=str(db_path)) db.connect() # 注意:你原测试用全局实例连接本地已有库才能查到8张表,临时空库必须先执行业务建表逻辑 # 此处补全你业务的8张表CREATE TABLE语句,执行后commit # 示例: # db.execute("CREATE TABLE general_bill (...)") # db.execute("CREATE TABLE expenses (...)") # ... 补全剩余6张表建表语句 # db.connection.commit() query = """ SELECT name FROM sqlite_master WHERE type='table' """ db.execute(query) result = db.cursor.fetchall() db.close() assert len(result) == 8 class TestFile: def test_save_all_csv(self, tmpdir, monkeypatch): # 切换当前工作目录到临时目录,无需修改业务代码的相对路径逻辑,所有CSV自动输出到临时目录 monkeypatch.chdir(tmpdir) # 初始化临时测试库,建表并插入测试数据,避免读空表报错 db_path = tmpdir.join("test.db") db = Crud_db(database=str(db_path)) db.connect() db.execute("CREATE TABLE general_bill (id INT, content TEXT)") db.execute("CREATE TABLE expenses (id INT, amount FLOAT)") db.execute("CREATE TABLE total (id INT, total FLOAT)") # 插入测试数据 db.execute("INSERT INTO general_bill VALUES (1, 'test')") db.execute("INSERT INTO expenses VALUES (1, 100.0)") db.execute("INSERT INTO total VALUES (1, 200.0)") db.connection.commit() db.close() # 执行全量导出 db.save_to_csv() # 校验目标CSV文件全部生成 expected_files = [ "general_bill_all.csv", "expenses_all.csv", "total_day_all.csv" ] for file_name in expected_files: target_file = tmpdir.join(file_name) assert os.path.exists(target_file), f"导出文件{file_name}未生成" # 可选:校验CSV内容正确性 df = pd.read_csv(str(target_file)) assert len(df) == 1 def test_save_specified_day_csv(self, tmpdir, monkeypatch): monkeypatch.chdir(tmpdir) db_path = tmpdir.join("test.db") db = Crud_db(database=str(db_path)) db.connect() # 建表并插入指定日期测试数据 db.execute("CREATE TABLE general_bill (id INT, date_g TEXT)") db.execute("CREATE TABLE expenses (id INT, date TEXT)") db.execute("CREATE TABLE total (id INT, date TEXT)") test_day = "2024-01-01" db.execute(f"INSERT INTO general_bill VALUES (1, '{test_day}')") db.execute(f"INSERT INTO expenses VALUES (1, '{test_day}')") db.execute(f"INSERT INTO total VALUES (1, '{test_day}')") db.connection.commit() db.close() # 执行指定日期导出 db.save_to_csv(day=test_day) # 校验对应日期的CSV文件生成 expected_files = [ f"general_bill_{test_day}.csv", f"expenses_{test_day}.csv", f"total_day_{test_day}.csv" ] for file_name in expected_files: assert os.path.exists(tmpdir.join(file_name))
关键注意事项
- 所有测试用例单独初始化
Crud_db实例,测试完成后主动调用close()释放数据库连接,从根源避免文件锁占用报错 - 测试生成的所有文件(数据库、CSV)全部放在
tmpdir临时目录下,测试结束后pytest会自动清理,不会残留垃圾文件到项目目录 - 校验文件存在性时必须指向具体文件路径,不能直接对文件夹调用读方法
- 用
monkeypatch.chdir(tmpdir)切换工作目录,不需要修改原有业务代码的相对路径写文件逻辑,就能实现测试文件隔离
内容的提问来源于stack exchange,提问作者zaki_zardo
相关产品推荐
相关产品推荐

