ruff (lint) 与 pytest 工作原理动画

静态分析「看代码」 vs 动态测试「跑代码」——两者都是外部工具,都不会把自己的逻辑写进你的业务代码

① 两条完全不同的路线

🔍 ruff / lint(静态分析)

# 把源码当“文本”读入 # 解析成 AST(语法树) # 用规则匹配,输出报告 # ❌ 不运行你的程序
关注:风格、未使用变量、import 排序、潜在 bug 写法……

🧪 pytest(动态测试)

# 收集 test_* 函数 # 真正调用你的函数 # 对 assert 求值 → 红/绿 # ✅ 真的运行你的程序
关注:逻辑对不对、结果是否符合预期、异常是否抛出……
👉 二者都是独立的工具 + 独立的文件,运行时不会混入被测业务代码。

② 项目结构 点击文件夹展开 · 点文件看代码

📦 pytest_doc/ (点击节点展开/折叠)

  • ▸📁 src/
    • 🐍 calculator.py
  • ▸📁 tests/
    • 🧪 test_calculator.py
  • ⚙️ 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
0%
lint 看代码、pytest 跑代码,二者互补: 前者保证“写得规范、没有低级错误”,后者保证“逻辑真的对”。 都不会污染你的业务代码。