DRF集成测试中CoreAPIClient触发psycopg2连接关闭异常
解决DRF测试中CoreAPIClient报「Interface error: connection already closed」的问题
我之前帮朋友排查过几乎一模一样的问题——Django 1.11 + DRF的环境里,APIClient测试完全正常,但一用CoreAPIClient写集成测试就炸,外部工具(Postman、coreapi-cli)却能正常调用。本质上是测试框架的数据库连接管理和CoreAPIClient的调用机制不兼容导致的,下面给你几个亲测有效的解决方案:
1. 手动确保测试中的数据库连接活跃
APITestCase会自动管理事务和连接,但CoreAPIClient的调用可能绕过了这个机制,导致连接被提前关闭。在使用CoreAPIClient前手动触发连接即可:
from django.db import connection from coreapi import CoreAPIClient from rest_framework.test import APITestCase class AccountAPITest(APITestCase): def test_coreapi_list_accounts(self): # 先确保数据库连接是活跃状态 connection.ensure_connection() client = CoreAPIClient() # 先获取API schema(如果你的API用了coreapi文档) schema = client.get('/docs/') # 调用接口动作 response = client.action(schema, ['accounts', 'list']) self.assertEqual(len(response), 1) # 假设你有一条测试数据
2. 避免在同一个测试方法里混用APIClient和CoreAPIClient
如果在同一个测试方法里先跑了APIClient的请求,它会触发事务回滚,可能直接关闭了数据库连接,后续CoreAPIClient再调用就会报错。要么分开测试方法,要么切换客户端时重置连接:
def test_clients_separately(self): # 先用APIClient测试 api_response = self.client.get('/api/accounts/') self.assertEqual(api_response.status_code, 200) # 重置数据库连接 from django.db import connection connection.close() connection.ensure_connection() # 再用CoreAPIClient测试 core_client = CoreAPIClient() schema = core_client.get('/docs/') accounts = core_client.action(schema, ['accounts', 'list']) self.assertEqual(len(accounts), 1)
3. 调整测试用例的基类
APITestCase默认用事务包裹每个测试,结束后回滚,这可能和CoreAPIClient的HTTP请求机制冲突。你可以尝试用SimpleTestCase或者TransactionTestCase代替:
- 如果你不需要数据库数据(比如测试静态端点),用
SimpleTestCase:
from django.test import SimpleTestCase from coreapi import CoreAPIClient class StaticAPITest(SimpleTestCase): def test_coreapi_health_check(self): client = CoreAPIClient() response = client.get('/api/health/') self.assertEqual(response.status_code, 200)
- 如果需要数据库数据,用
TransactionTestCase(它不会自动回滚,需要手动清理数据):
from django.test import TransactionTestCase from coreapi import CoreAPIClient from myapp.models import Account class AccountCoreAPITest(TransactionTestCase): def setUp(self): # 手动创建测试数据 Account.objects.create(name="Test Account") def test_coreapi_get_account(self): client = CoreAPIClient() schema = client.get('/docs/') account = client.action(schema, ['accounts', 'retrieve'], params={'id': 1}) self.assertEqual(account['name'], "Test Account")
4. 调整测试环境的数据库连接配置
检查你的settings.py里是否设置了CONN_MAX_AGE,如果测试环境里这个值太高,可能导致连接被复用但已经失效。可以在测试时强制关闭连接复用:
# settings.py import sys if 'test' in sys.argv: DATABASES['default']['CONN_MAX_AGE'] = 0 # 每次请求都用新连接
为什么Postman/coreapi-cli正常?
因为这些外部工具是通过HTTP请求访问测试服务器,连接是独立于测试进程的,不会受到测试框架的事务/连接管理影响。而测试里的CoreAPIClient是在测试进程内部调用,和APITestCase的连接生命周期绑定了,才会出现冲突。
内容的提问来源于stack exchange,提问作者Pitt
相关产品推荐
相关产品推荐

