NEWS DETAIL

Flask 笔记十六:用 pytest 测 Flask 应用

发布时间:2026/10/25 0:29:17 · 栏目:资讯中心

尧图网络原创建站知识分享正文
上一篇我们把flask create-admin、flask db upgrade写进了部署流程。功能越堆越多改一处、怕别处坏——手动点浏览器很快不够用了。这一篇做一件事用 pytest Flask 测试客户端给路由和 JSON API 写自动化测试。例子仍是通用的Note备忘录项目不涉及任何真实业务。1. 学完后你能做什么用pytest跑测试比 unittest 写法更短用app.test_client()模拟 HTTP 请求不真开浏览器测试 登录、受保护页面、JSON API用 临时 SQLite 内存库测试不污染开发数据库用 fixture 复用「已登录客户端」2. 为什么需要测试方式优点缺点手动点页面直观慢、易漏、难回归脚本 curl适合 API难组「先登录再访问」pytest test_client快、可重复、改完一键跑要先写一点代码入门目标改完代码跑pytest30 秒内知道「列表页还能不能打开、未登录会不会 401」。3. 安装依赖pip install pytest可选覆盖率后面再用pip install pytest-cov项目根目录建tests/文件夹myproject/├── app/├── tests/│ ├── __init__.py # 空文件即可│ ├── conftest.py # 公共 fixture│ └── test_notes.py # 具体测试├── pytest.ini # 可选配置└── requirements-dev.txt # 可选pytest 放这里4. 测试用的 App内存数据库测试 不要连开发用的 MySQL/SQLite 文件否则可能删光数据。常见做法测试配置里用 内存 SQLitetests/conftest.pyimport pytestfrom app import app as flask_app, dbfrom app.models import User, Notepytest.fixturedef app():flask_app.config.update({TESTING: True,SQLALCHEMY_DATABASE_URI: sqlite:///:memory:,SECRET_KEY: test-secret,WTF_CSRF_ENABLED: False, # 测试里简化 POST见下文})with flask_app.app_context():db.create_all()yield flask_appdb.session.remove()db.drop_all()pytest.fixturedef client(app):return app.test_client()pytest.fixturedef user(app):from werkzeug.security import generate_password_hashu User(nametester, pwdgenerate_password_hash(pass123), is_adminFalse)db.session.add(u)db.session.commit()return upytest.fixturedef auth_client(client, user):已登录的 test client。client.post(/login/, data{name: tester,password: pass123,})return client要点TESTING True部分扩展会走测试模式:memory:库在内存里测完drop_allWTF_CSRF_ENABLED False表单 POST 不必每次带 token只限测试生产必须开 CSRF若你坚持测 CSRF可在 POST 里从页面 parsecsrf_token入门先关省事。5. 第一个测试首页能打开tests/test_notes.pydef test_index(client):resp client.get(/)assert resp.status_code 200运行pytest# 或pytest tests/test_notes.py -v-v看每条用例名失败时会打印断言差异。6. 测未登录 vs 已登录假设列表页/notes/有login_requireddef test_note_list_redirects_when_anonymous(client):resp client.get(/notes/, follow_redirectsFalse)assert resp.status_code in (302, 401) # redirect 登录 或 直接 401def test_note_list_ok_when_logged_in(auth_client):resp auth_client.get(/notes/)assert resp.status_code 200assert b备忘录 in resp.data or bnotes in resp.data.lower()follow_redirectsFalse只看 第一步 响应方便断言 302。7. 测 POST新增一条备忘录def test_create_note(auth_client):resp auth_client.post(/notes/add/, data{title: pytest 写的标题,content: 内容,}, follow_redirectsTrue)assert resp.status_code 200assert bpytest in resp.data配合conftest里已登录的auth_client不用手写 Session。8. 测 JSON API接第十三篇def test_api_notes_unauthorized(client):resp client.get(/api/notes/)assert resp.status_code 401data resp.get_json()assert data[ok] is Falsedef test_api_notes_json(auth_client):resp auth_client.get(/api/notes/)assert resp.status_code 200data resp.get_json()assert data[ok] is Trueassert items in dataassert isinstance(data[items], list)get_json()比json.loads(resp.data)简洁。POST JSONdef test_api_create_note(auth_client):resp auth_client.post(/api/notes/,json{title: API 测试, content: },)assert resp.status_code 201data resp.get_json()assert data[ok] is Trueassert data[item][title] API 测试9. 在测试里准备数据def test_list_shows_own_notes_only(app, auth_client, user):other User(nameother, pwdx)db.session.add(other)db.session.flush()db.session.add(Note(title我的, user_iduser.id))db.session.add(Note(title别人的, user_idother.id))db.session.commit()resp auth_client.get(/notes/)assert b我的 in resp.dataassert b别人的 not in resp.data业务规则只看自己的备忘录适合写成测试以后改note_service时不容易回归。10.pytest.ini可选项目根目录[pytest]testpaths testspython_files test_*.pyaddopts -v --tbshort以后只打pytest即可。11. 和 note_service 的关系接第十篇视图越薄测试越好写# tests/test_note_service.pydef test_list_notes_for_user_filters_by_owner(app, user):from app.note_service import list_notes_for_userfrom app.models import Note, Userother User(nameo, pwdx)db.session.add_all([other, Note(titlea, user_iduser.id)])db.session.commit()page list_notes_for_user(user.id, page1, per_page10)titles [n.title for n in page.items]assert titles [a]service 测试查数据库、规则对不对client 测试路由、登录、HTTP 状态码、模板/API 格式两层都写会啰嗦入门 先测 client 关键路径复杂查询再抽 service 单测。12. 流程示意pytest│▼conftestapp 内存库 client│▼test_xxxclient.get/post│▼Flask 路由 → 视图 → service → DB内存│▼assert status_code / JSON / 页面字节开发改代码 → pytest → 绿/红│└── 红修完再提交13. 新手常踩的 6 个坑没app.app_context()— fixture 里with flask_app.app_context():包create_all。测试连了真库 — 务必TESTING 内存 URI。CSRF 导致 POST 400 — 测试配置关 CSRF或表单带 token。Session 不共享 — 同一client对象上先post /login/再get /notes/。断言中文乱码 —resp.data是 bytes用b备忘录 in resp.data。测完不清理 — fixture 末尾drop_all或用:memory:。14. 小结记住五件事pytesttests/目录conftest.py里 app / client / auth_client fixture内存 SQLite不碰开发库client.get/postget_json()测 API关键路径未登录 401、登录后 200、只能看自己的数据十六篇下来你已经具备写功能 → 分层 → 配置 → API → 部署 → CLI → 自动化测试 的完整入门闭环。
✦

本文为尧图网络原创建站知识分享。想针对自身行业获取定制化建站方案?欢迎咨询,资深顾问免费为你出思路。

RELATED

相关 资讯推荐

MORE

更多 新鲜资讯

JMeter入门实战:从零构建HTTP接口性能测试脚本与结果分析
2026/10/21 11:24:40

JMeter入门实战:从零构建HTTP接口性能测试脚本与结果分析

1. 项目概述:从零开始,用JMeter搞定HTTP性能测试 刚接触性能测试的新手,或者是从功能测试转过来的朋友,一听到“压测”两个字,心里可能就有点发怵。工具那么多,概念那么杂,从哪儿下手呢&#xf…

Earendel: 一个纯TS写的POSIX兼容的微内核Web操作系统
2026/10/24 20:39:51

Earendel: 一个纯TS写的POSIX兼容的微内核Web操作系统

最近我用TypeScript写了一个运行在浏览器里的Web操作系统 Earendel(目前已知的距离地球最遥远的恒星)。开发它的初衷主要是为了Linux和操作系统课程的教学。市面上绝大多数Web OS项目,要么只是做了一个长得像Windows/macOS的网页UI拼盘&#…

5分钟掌握Windows防撤回神器:让微信QQ撤回消息无处遁形[特殊字符]
2026/10/19 6:46:54

5分钟掌握Windows防撤回神器:让微信QQ撤回消息无处遁形[特殊字符]

5分钟掌握Windows防撤回神器:让微信QQ撤回消息无处遁形🚀 【免费下载链接】RevokeMsgPatcher :trollface: A hex editor for WeChat/QQ/TIM - PC版微信/QQ/TIM防撤回补丁(我已经看到了,撤回也没用了) 项目地址: http…

从零制作同人动画:技术路线、流程与实战避坑指南
2026/10/24 7:09:28

从零制作同人动画:技术路线、流程与实战避坑指南

1. 先搞清楚这个“粉丝动画”到底是什么,以及它能解决什么问题看到“五条悟VS宿傩/咒术回战粉丝动画”这个标题,很多人的第一反应可能是去找一个现成的视频。但如果你是一个想自己动手创作、或者想了解这类作品背后技术流程的创作者,这个标题…

闭源降价80%,开源却在涨价:AI定价的交叉路口
2026/10/24 22:16:44

闭源降价80%,开源却在涨价:AI定价的交叉路口

8月6日,两条价格曲线悄然交汇。 一条向下:OpenAI把GPT-5.6 Luna的输出价格从6美元砍到1.2美元/百万Token,降幅80%。另一条向上:同一天,DeepSeek公告全线涨价,措辞是"涨幅较大",非试探…

产线三防平板选哪个牌子?5个品牌实测告诉你别瞎买
2026/10/23 10:16:26

产线三防平板选哪个牌子?5个品牌实测告诉你别瞎买

产线三防平板选哪个牌子?5个品牌实测告诉你别瞎买经常有工厂朋友拿着网上的"三防平板十大品牌排行榜"来问我:到底选哪个?说实话排行榜看看就行,真正选型得看你产线什么场景。今天挑五个在产线数字化里用得比较多的品牌—…

看完这篇,还想了解更多?

预约尧图网络顾问一对一沟通,针对你的行业与现状给出建站建议,全程免费。

免费咨询