① 两条完全不同的路线
🔍 ruff / lint(静态分析)
# 把源码当“文本”读入
# 解析成 AST(语法树)
# 用规则匹配,输出报告
# ❌ 不运行你的程序
关注:风格、未使用变量、import 排序、潜在 bug 写法……
🧪 pytest(动态测试)
# 收集 test_* 函数
# 真正调用你的函数
# 对 assert 求值 → 红/绿
# ✅ 真的运行你的程序
关注:逻辑对不对、结果是否符合预期、异常是否抛出……
👉 二者都是独立的工具 + 独立的文件,运行时不会混入被测业务代码。
② 项目结构 点击文件夹展开 · 点文件看代码
📦 pytest_doc/ (点击节点展开/折叠)
-
▸📁 src/
-
▸📁 tests/
- ▸⚙️ pytest.ini
- ▸🦀 pyproject.toml
- ▸📋 requirements.txt
- ▸📖 README.md
最后一层(文件)就是代码细节,点击右侧查看 →
👉 点击左侧任意文件查看代码
// 选择一个文件…
③ ruff 原理 静态分析 · 不执行
📄源码文本calculator.py
→
🔡词法分析tokens
→
🌳语法树AST
→
📐规则匹配E/F/I/B/UP
→
📋报告不改逻辑
10import pytest
11from src.calculator
import add, subtract, multiply, divide, is_even
12
13def test_add():
14 assert add(
2,
3) ==
5
15 unused =
42 # 没用到的变量
ruff 全程只是“阅读 + 比对规则”,从不执行 add()。所以它不会把检查逻辑写进代码。
④ ruff check --fix 会改写「你的源码格式」
修复前
from src.calculator import add, subtract, multiply, divide, is_even
I001 Import block is un-sorted
修复后(自动排序)
from src.calculator import
All checks passed! ✅
⚠️ 注意区别:它修改的是你自己的代码格式(排序/空格/引号),
而不是“把 lint 规则塞进你的代码”。两回事。
同理 ruff format . 只负责统一排版,不改变程序行为。
⑤ pytest 原理 动态执行 · 真跑代码
🔎收集test_*
→
⚙️调用函数真的运行
→
⚖️assert 求值比较结果
→
🚦红 / 绿pass/fail
def test_divide_by_zero():
with pytest.raises(ValueError):
divide(1, 0) # ← pytest 真的调用它,看是否抛异常
pytest 真实执行了 divide(1,0),捕获到 ValueError → 这条用例变绿。
⑥ 完整流程(开发 / CI 质量门禁)
✍️写代码
→
🔧ruff --fix修 lint
→
🎨ruff format统一排版
→
🧪pytest跑测试
→
🚀合并/部署
# 一行搞定质量门禁:任意一步失败则整体失败
ruff check . && ruff format --check . && pytest
lint 看代码、pytest 跑代码,二者互补:
前者保证“写得规范、没有低级错误”,后者保证“逻辑真的对”。
都不会污染你的业务代码。