FastAPI 新手入门第 12 篇:不靠手点 /docs,用测试确认接口没坏

发布时间:2026/7/14 20:17:58

FastAPI 新手入门第 12 篇:不靠手点 /docs,用测试确认接口没坏
到目前为止我们验证接口的方式都是启动服务打开/docs手动填入参数点调用。这个方法有两个问题一是慢每次改了代码都要重新打开浏览器试一遍二是不可重复你试了三个接口后端还会多出几个你很难知道自己有没有漏测。这篇我把测试加上。用 FastAPI 自带的TestClient不启动真实服务也能发 HTTP 请求。写好几条测试命令行跑一遍就能确认所有接口都正常。做完后你在终端敲一条命令十几条断言自动跑完全部通过。为什么测试不是高级话题很多人觉得测试是代码写完之后再做的高级优化。这个想法在前后端开发里都挺常见的但放在后端接口开发上尤其危险。接口是对外的。前端调用你写的接口改了转发逻辑、加了字段校验、换了数据库操作方式接口行为都可能变。如果每次依赖肉眼在/docs里点一遍大概率会漏。测试代码解决的问题很具体你改了代码跑一条测试确认接口行为跟你预期的一样。这就够了。先装依赖需要两个包pytest是测试框架httpx是TestClient背后真正发 HTTP 请求的库pip install pytest httpx然后在pyproject.toml里加上dependencies [ fastapi[standard]0.115.0, pydantic-settings2.0.0, sqlalchemy2.0, pytest8.0, httpx0.27, ]装上依赖之后用pytest命令就能自动发现项目里的测试文件。创建 tests 目录和测试夹具新建tests/__init__.py空文件就行然后在tests/conftest.py里写测试夹具。conftest.py是 pytest 的特殊文件。写在里面的 fixture 会被同目录下的所有测试文件自动共享。我先写两个 fixtureimportpytestfromfastapi.testclientimportTestClientfromsqlalchemyimportcreate_enginefromsqlalchemy.ormimportsessionmakerfromapp.databaseimportBase,get_dbfromapp.mainimportapp TEST_DATABASE_URLsqlite:///./test.dbenginecreate_engine(TEST_DATABASE_URL,connect_args{check_same_thread:False},)TestingSessionLocalsessionmaker(autocommitFalse,autoflushFalse,bindengine)pytest.fixturedefdb():Base.metadata.create_all(bindengine)dbTestingSessionLocal()try:yielddbfinally:db.close()Base.metadata.drop_all(bindengine)pytest.fixturedefclient(db):defoverride_get_db():yielddb app.dependency_overrides[get_db]override_get_dbwithTestClient(app)asc:yieldc app.dependency_overrides.clear()重点看两个地方。dbfixture 做了三件事建表、给测试用例一个数据库会话、用例跑完后删表。这样每个测试用例都用干净的数据库开始不会互相影响。clientfixture 里最关键的一行app.dependency_overrides[get_db]override_get_db这行告诉 FastAPI“当接口函数里写了Depends(get_db)时换成用测试数据库别用线上数据库”。这样测试跑的时候创建的商品写到test.db里不会影响fastapi_beginner_lab.db。app.dependency_overrides是 FastAPI 为测试专门设计的。它让你能在不修改接口代码的前提下替换任何依赖。写第一条测试确认服务能跑新建tests/test_health.pydeftest_read_root(client):responseclient.get(/)assertresponse.status_code200assertresponse.json(){message:Hello FastAPI}deftest_ping(client):responseclient.get(/ping)assertresponse.status_code200assertresponse.json(){message:pong}deftest_health(client):responseclient.get(/health)assertresponse.status_code200dataresponse.json()assertdata[status]okassertapp_nameindataassertenvindata这三条的写法一模一样client.get(/path)发一个 GET 请求。检查status_code是不是期望值。检查返回的 JSON 内容。client.get和client.post用起来就像requests库但不需要启动真实服务。写接口测试创建商品和 404新建tests/test_items.py。测试有状态的接口创建、查询比测试无状态接口首页、健康检查多一步需要处理 token 认证。deftest_create_item(client):responseclient.post(/items,json{name:Test Hammer,price:9.99,is_offer:False,},headers{x-token:secret-token},)assertresponse.status_code200dataresponse.json()assertdata[name]Test Hammerassertdata[price]9.99assertdata[is_offer]isFalseassertidindataassertcost_pricenotindataassertcreated_bynotindatadeftest_list_items(client):先创建一条数据再确认列表能查到它。client.post(/items,json{name:Test Item,price:5.0},headers{x-token:secret-token},)responseclient.get(/items,headers{x-token:secret-token})assertresponse.status_code200dataresponse.json()assertisinstance(data,list)assertlen(data)1deftest_read_item_not_found(client):responseclient.get(/items/99999,headers{x-token:secret-token})assertresponse.status_code404assertresponse.json()[detail]Item not founddeftest_missing_token_returns_401(client):responseclient.get(/items)assertresponse.status_code401几条测试覆盖了最常见的场景测试验证什么test_create_item创建成功响应字段正确内部字段没泄露test_list_items创建后能从列表查到test_read_item_not_found不存在的 ID 返回 404test_missing_token_returns_401不带 token 被拒绝headers{x-token: secret-token}因为我们的依赖get_token_header需要这个头部测试里要带上。运行测试在项目根目录下pytest输出类似这样tests/test_health.py ... [ 37%] tests/test_items.py .... [100%]如果某个测试失败pytest 会精确告诉你是哪一行断言不通过以及实际值和期望值的差异。想看得详细一点加-vpytest-v测试和 /docs 不是二选一有了测试不是说你就不用/docs了。/docs更适合在开发时代替网页客户端快速试试接口能不能走通。测试更适合在每次改完代码后确认所有接口行为都没变。这两件事不冲突但不要把/docs当做测试的替代品。动手改一下给测试加一条验证创建商品时不带必填字段会返回 422deftest_create_item_missing_name(client):responseclient.post(/items,json{price:9.99},headers{x-token:secret-token},)assertresponse.status_code422跑pytest确认这条测试通过。如果能自动验证 422 错误就说明你已经能给接口写测试了。到这里这篇的目标已经完成我们用 TestClient 写了健康检查和商品接口的测试。我们用 dependency_overrides 让测试用独立的数据库。我们运行 pytest所有测试通过。本文代码https://github.com/tanghaojin/fastapi-beginner-lab/tree/article-12-testing下一篇解决另一个问题现在接口认证靠写死secret-token下一篇换成真正的登录流程。参考资料FastAPI Testing: https://fastapi.tiangolo.com/tutorial/testing/pytest 文档: https://docs.pytest.org/

相关新闻

深度学习十大核心算法:从CNN到扩散模型的原理与实战详解

深度学习十大核心算法:从CNN到扩散模型的原理与实战详解

2026/7/14 20:17:58

在深度学习领域,算法模型的发展已经从早期的卷积神经网络(CNN)和循环神经网络(RNN),逐步演进到以 Transformer 为代表的自注意力机制模型,再到生成对抗网络(GAN)和扩散模…

HTML5基础标签详解与前端开发实践指南

HTML5基础标签详解与前端开发实践指南

2026/7/14 20:17:58

1. HTML基础标签概述HTML(超文本标记语言)是构建网页的基础,由一系列标签组成。每个标签都有特定的语义和功能,它们像积木一样组合起来形成完整的网页结构。作为前端开发的基石,掌握HTML标签是每个开发者的必修课。在H…

FLASH闪存(STM32)

FLASH闪存(STM32)

2026/7/14 20:07:57

简介:STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程读写FLASH的用途:利用程序存储器的剩余空间来保存掉电不丢失的用户数据通过…

C++实现凯撒密码:从原理到实战的完整编程指南

C++实现凯撒密码:从原理到实战的完整编程指南

2026/7/14 21:38:02

1. 项目概述与核心价值最近在整理一些基础的安全编程资料,发现很多朋友对古典密码学很感兴趣,但又觉得理论枯燥,难以动手。正好,用C实现一个凯撒密码的加密解密工具,是一个绝佳的练手项目。它不像现代加密算法那样涉及…

618 AI购物战正酣,云南GEO正规优化公司哪家好?看老板咋选

618 AI购物战正酣,云南GEO正规优化公司哪家好?看老板咋选

2026/7/14 21:38:02

618变局:AI购物全面爆发,品牌如何抢占推荐先机?你发现没有?今年618最大的变化,早已不是各大平台此起彼伏的价格战,而是AI购物模式的全面落地,彻底改写了消费市场的竞争规则。京东牵手腾讯AI&…

ASP架构的轻量级在线考试平台,含随机组卷、自动阅卷与后台题库管理

ASP架构的轻量级在线考试平台,含随机组卷、自动阅卷与后台题库管理

2026/7/14 21:38:02

本文还有配套的精品资源,点击获取 简介:这是一个基于经典ASP技术构建的在线考试解决方案,专为Windows服务器环境(IIS)设计,支持Access或SQL Server数据库。学生登录后可参与随机抽题考试,系统…

多国音乐热词实时热力图工具:含清洗数据、Python+D3可视化代码与一键运行说明

多国音乐热词实时热力图工具:含清洗数据、Python+D3可视化代码与一键运行说明

2026/7/14 21:38:02

本文还有配套的精品资源,点击获取 简介:一套开箱即用的音乐关键词地理分布分析工具,基于全球主流榜单真实数据,自动生成各国高频词热力图和时间趋势图。数据已清洗完毕,包含去重、标准化、国家映射、词频统计等预处…

飞算Java实战:制造业设备预测性维护与工单闭环系统

飞算Java实战:制造业设备预测性维护与工单闭环系统

2026/7/14 21:38:02

从设备台账、实时采集到风险预警、维修派工和备件补货,一次围绕制造现场运维链路完成的 Java 项目实践。在制造业现场,设备维护往往不是“等坏了再修”这么简单。温度、振动、电流等数据持续变化,异常一旦没有及时发现,后续可能涉…

鱼池发黑发臭就是硝化系统崩了?9成人第一步就判断错了

鱼池发黑发臭就是硝化系统崩了?9成人第一步就判断错了

2026/7/14 21:28:01

很多鱼友一看到自家鱼池的水变得发黑发臭,第一反应就是“完了,硝化系统崩溃了”,然后赶紧换水、下药、加硝化菌,折腾一圈下来,水质反而更糟了。事实上,根据南京比德园艺服务有限公司过去十余年服务超500个项…

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

2026/7/14 10:03:09

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator作为Unity游戏社区中最成熟的文本翻译解决方…

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

2026/7/13 20:43:19

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持 【免费下载链接】raspberrypi-kernel It provides openEuler kernel source for Raspberry Pi 项目地址: https://gitcode.com/openeuler/raspberrypi-kernel 前往项目官网免费下载&…

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

2026/7/13 20:43:10

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧 【免费下载链接】integration-test The repo contains test suits for system integration test 项目地址: https://gitcode.com/openeuler/integration-test 前往项目官网免费下载:…

XUnity.AutoTranslator 游戏实时翻译插件:从原理到实战的完整指南

XUnity.AutoTranslator 游戏实时翻译插件:从原理到实战的完整指南

2026/7/14 0:06:37

1. 项目概述:当游戏语言成为一堵墙作为一名玩了十几年日系、欧美独立游戏的“老油条”,我太懂那种面对一款心仪已久、画风玩法都戳中G点的游戏,却因为语言不通而望而却步的痛了。尤其是那些基于Unity引擎开发的、体量不大但内容精良的作品&am…

2026普通文员学数据分析的价值

2026普通文员学数据分析的价值

2026/7/14 0:06:37

一、2026年普通文员学习数据分析的必要性随着数字化转型加速,数据分析技能正逐渐成为职场基础能力。普通文员学习数据分析可以提升工作效率、增强竞争力,并为职业转型提供更多可能性。二、数据分析对文员的价值自动化办公:通过数据分析工具&a…

2026从计划员到主管,生产管理者学数据分析有用吗?

2026从计划员到主管,生产管理者学数据分析有用吗?

2026/7/14 0:06:37

一、生产管理领域的职业发展路径 从计划员到主管的角色转变,是生产管理者职业发展的典型路径。计划员主要负责生产排程、库存管理和资源协调等基础工作,而主管则需要承担团队管理、决策支持和效率优化等更高级别的职责。这种转变不仅仅是职位的提升&…