Flask test_client 怎么用?如何测试接口、上下文和异常?
简化版
Flask 的 test_client() 可以在不启动真实 HTTP 服务的情况下测试路由。它能发送 GET/POST 请求、传 JSON、检查状态码和响应体,常配合 pytest fixture 和应用工厂创建独立测试 app。
详细版
@pytest.fixture
def client():
app = create_app(TestingConfig)
return app.test_client()
def test_ping(client):
resp = client.get("/ping")
assert resp.status_code == 200
assert resp.get_json() == {"ok": True}
测试时应使用测试配置、测试数据库、隔离外部依赖。面试回答要强调:test_client 走 Flask 请求处理链,但不经过真实网络,因此速度快、稳定,适合接口级测试。
完整版教学
一、为什么不用真实服务测试所有接口
启动真实服务器再发 HTTP 请求更接近生产,但慢、复杂、端口冲突多。多数接口逻辑可以通过 Flask test client 直接测试 WSGI 应用。
pytest -> test_client -> Flask app -> response
它仍会经过路由、before_request、视图、after_request、错误处理等链路。
二、应用工厂和测试配置
测试最好通过 create_app(TestingConfig) 创建 app,保证配置可控。比如关闭真实邮件发送、使用测试数据库、开启 TESTING。
class TestingConfig:
TESTING = True
SQLALCHEMY_DATABASE_URI = "sqlite://"
没有应用工厂时,测试不同配置会很别扭。
三、如何发送 JSON 请求
test client 可以用 json= 参数发送 JSON,并自动设置 Content-Type。
resp = client.post("/users", json={"name": "Ada"})
assert resp.status_code == 201
响应 JSON 用 resp.get_json() 读取,比手动解析 resp.data 更清晰。
四、上下文怎么测试
有些函数依赖 request、g、current_app。可以通过请求触发,也可以用 app.app_context() 或 app.test_request_context() 创建上下文。
with app.app_context():
assert current_app.config["TESTING"]
但不要过度依赖上下文测试内部函数。业务逻辑最好拆成普通函数,减少 Flask 全局代理依赖。
五、数据库测试如何隔离
接口测试常需要准备数据和清理数据。可以每个测试使用事务回滚、临时数据库或 fixture 重建表。
setup data -> request -> assert -> rollback/cleanup
测试之间不能互相依赖顺序,否则一批跑没问题,单独跑就失败。
六、异常和错误响应怎么测
要测试 400、404、500 等错误格式,确认 errorhandler 正常工作。测试模式下异常传播行为可能和生产配置不同,要按测试目的配置。
resp = client.get("/missing")
assert resp.status_code == 404
assert "error" in resp.get_json()
如果你想测试异常是否抛出,可以配置 PROPAGATE_EXCEPTIONS。
七、认证和 Session 怎么测
需要登录态时,可以走登录接口拿 cookie,也可以直接操作 session。前者更像用户行为,后者更快,适合准备测试状态。
with client.session_transaction() as sess:
sess["user_id"] = 1
如果项目使用 token 鉴权,就在请求头里传 Authorization。测试要覆盖未登录、权限不足和正常授权三类路径。
八、测试粒度怎么分
test_client 适合接口级测试,但业务计算逻辑最好拆成普通函数单测。这样失败时能快速定位:是路由/序列化错,还是业务逻辑错。
unit test: service/function
interface test: route + request chain
e2e test: real server + external integration
不要把所有场景都堆到接口测试里,否则测试慢且定位困难。
九、常见误区与追问
- 误区:test_client 不经过 Flask 请求链。 它会经过应用请求处理,只是不走真实网络。
- 误区:测试可以用生产数据库。 必须隔离,避免污染真实数据。
- 误区:只测 200 成功路径就够。 还要测错误、边界和权限。
- 追问:如何传 header?
client.get(..., headers={...})。 - 追问:如何保持登录状态? 用 session_transaction 或测试登录接口。
- 追问:fixture 为什么重要? 统一创建 app/client/db,避免重复和污染。
- 追问:如何测试文件上传? 用
data和文件对象,设置 multipart。
十、加强记忆
Flask test_client 记成“不起服务也能走请求链”。配合应用工厂、测试配置和 pytest fixture,测状态码、JSON、上下文、错误和数据库隔离。它适合快速接口测试,少数端到端场景再用真实 HTTP。