使用PyTest测试Delete接口遇404:如何摆脱数据库ID依赖?
解决CRUD接口测试中依赖数据库ID的问题
你完全可以不依赖数据库现有ID,让删除、查询测试稳定通过,核心思路有两种:Mock数据库访问层(完全脱离真实数据库),或者使用独立测试数据库+前置数据准备(可控的真实数据交互)。下面分别展开并结合你的代码给出实现方案:
方案一:Mock数据库层,完全脱离真实数据库
这种方式不需要和任何真实数据库交互,通过Mock掉接口里操作数据库的函数/方法,模拟“ID存在”的场景,直接验证接口的逻辑和返回格式。
比如你的删除接口/access-issues/delete/<id>,本质是调用数据库的查询(确认ID存在)和删除操作,你可以Mock这两个数据库操作的返回值,让它们始终返回“成功”。
修改你的测试代码示例:
假设你的接口逻辑里是调用access_issue_service.delete_access_issue(id)这个服务层方法来操作数据库,我们可以Mock这个方法:
@patch('flask_jwt_extended.view_decorators.verify_jwt_in_request') @patch('your_app.module.access_issue_service.delete_access_issue') # 替换成实际的数据库操作路径 def test_sites_delete(mock_delete, mock_verify, client): # 模拟删除方法返回成功(比如返回True表示删除成功) mock_delete.return_value = True response = client.delete('/access-issues/delete/3') # 随便用一个ID都可以 assert response.status_code == 200 assert b'Success: Access Issue Deleted Successfully' in response.data # 验证Mock方法被正确调用,传入了对应的ID mock_delete.assert_called_once_with('3')
同理,查询单个ID的测试也可以Mock查询方法,返回预设的测试数据:
@patch('flask_jwt_extended.view_decorators.verify_jwt_in_request') @patch('your_app.module.access_issue_service.get_access_issue_by_id') def test_access_by_id(mock_get, mock_verify, client): # 模拟查询返回预设的访问问题数据 mock_get.return_value = { 'id': '3', 'date_time': '2020-05-21', 'asset_label': '123456', # 其他字段... } response = client.get('/access-issues/get/3') assert response.status_code == 200 assert b'Success: Access Issue fetched Successfully' in response.data mock_get.assert_called_once_with('3')
方案二:使用独立测试数据库+前置数据准备
如果想测试真实的数据库交互逻辑,可以用一个专门的测试数据库(和生产/开发库隔离),在每个测试前自动创建测试数据,测试后清理。
实现步骤:
- 配置测试环境的数据库连接(比如用SQLite内存库,或者专门的测试PostgreSQL库)。
- 写一个
pytest fixture,在测试前创建一条测试数据,返回其ID;测试后删除该数据或回滚事务。
代码示例:
import json import pytest from . import app, db # 假设你的应用有db实例 from .models import AccessIssue # 假设你的数据模型是AccessIssue @pytest.fixture def client(): # 配置测试数据库(比如用内存SQLite) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:' app.config['TESTING'] = True with app.app_context(): db.create_all() # 创建表 yield app.test_client() db.drop_all() # 测试后清理 @pytest.fixture def test_access_issue(client): # 创建一条测试数据,返回其ID issue = AccessIssue( date_time='2020-05-21', asset_label='123456', external_ref='123', building_name='Hilton', floor='one', room='123', reason='Cant enter', description='description', asset_id='1', picture_url='http://example.com', picture_width=1200 ) db.session.add(issue) db.session.commit() yield issue.id # 返回测试数据的ID # 测试后删除这条数据 db.session.delete(issue) db.session.commit() @patch('flask_jwt_extended.view_decorators.verify_jwt_in_request') def test_sites_delete(mock_verify, client, test_access_issue): # 使用fixture提供的真实存在的ID response = client.delete(f'/access-issues/delete/{test_access_issue}') assert response.status_code == 200 assert b'Success: Access Issue Deleted Successfully' in response.data @patch('flask_jwt_extended.view_decorators.verify_jwt_in_request') def test_access_by_id(mock_verify, client, test_access_issue): response = client.get(f'/access-issues/get/{test_access_issue}') assert response.status_code == 200 assert b'Success: Access Issue fetched Successfully' in response.data
两种方案的选择
- 如果只需要验证接口的HTTP逻辑、返回格式、权限校验,用Mock方案更高效,测试速度快,不依赖外部环境。
- 如果需要验证数据库操作的正确性(比如删除真的会从库中移除数据),选择测试数据库方案,能覆盖真实的业务流程。
内容的提问来源于stack exchange,提问作者Graham Patrick
相关产品推荐
相关产品推荐

