本节摘要:单元测试验证最小代码单元;集成测试验证模块间交互。本节配置 pytest 覆盖率门禁、JUnit 报告、Testcontainers 集成测试,并将 SonarQube quality gate 接入 PR 流水线——测试是 CI 的核心「门」。
阅读完本节,你应当能够:
--cov-fail-under 覆盖率阈值/ E2E \ ← CD 阶段,慢 / API \ / 集成测试 \ / 单元测试 \ ← CI 阶段,快 ───────────────
CI 阶段跑单元+部分集成;E2E 留给第3章 CD 预发环境。顺序不可颠倒——先 pytest 再 Selenium。
# tests/test_auth.py def test_login_returns_token(client): resp = client.post("/login", json={"user": "a", "pass": "b"}) assert resp.status_code == 200 assert "token" in resp.json()
CI 命令:
pytest --cov=app --cov-report=xml --cov-fail-under=80 -q
| 参数 | 作用 |
|---|---|
| --cov-fail-under=80 | 低于 80% 覆盖率 exit 1 |
| --cov-report=xml | 供 SonarQube 消费 |
| -q | 减少日志体积 |
GitHub Actions:
- run: pip install pytest pytest-cov - run: pytest --cov=app --cov-fail-under=80
<!-- pom.xml surefire --> <plugin> <artifactId>maven-surefire-plugin</artifactId> <configuration> <argLine>@{argLine} -Xmx1024m</argLine> </configuration> </plugin>
Jenkins JUnit 插件解析 target/surefire-reports/*.xml,PR 上显示「Tests: 847, Failures: 0」。
import pytest from testcontainers.postgres import PostgresContainer @pytest.fixture(scope="module") def db(): with PostgresContainer("postgres:15") as pg: yield pg.get_connection_url() def test_user_crud(db): # 真实 PostgreSQL,非 mock ...
CI 需 Docker-in-Docker 或 sibling docker socket。GitLab CI:
integration-test: services: [docker:dind] script: [pytest tests/integration -m "not slow"]
- run: mvn sonar:sonar -Dsonar.qualitygate.wait=true
| Sonar 指标 | 典型阈值 |
|---|---|
| Coverage | ≥ 80% on new code |
| Duplicated Lines | < 3% |
| Blocker Issues | 0 |
| Security Hotspots | reviewed |
⚠️ 常见坑:Flaky test——偶发失败让团队习惯「重跑就好」,quality gate 形同虚设。 flaky 测试要么修要么 quarantine,不能 ignore。
💡 关键直觉:Google 测试博客强调:不可靠的测试比没有测试更坏——它训练团队忽略红灯。
| 类型 | 速度 | 隔离 | CI 阶段 |
|---|---|---|---|
| 单元 | 毫秒 | mock 外部 | 必跑 |
| 集成 | 秒~分 | 真实 DB/消息队列 | 必跑 |
| E2E | 分钟~十分 | 全链路 | CD 预发 |
stage('Test') { parallel { stage('Unit') { steps { sh 'pytest tests/unit' } } stage('Integration') { steps { sh 'pytest tests/integration' } } } }
并行缩短 wall time,但共享 runner 资源——CPU 核数不足时反而更慢。
newman run collection.json -e staging.postman_environment.json \ --bail --reporters cli,junit
接口测试比 E2E 快,适合 CI 后期或 CD staging gate。
SonarQube 在 CI 跑 mvn sonar:sonar,检查 bug、vulnerability、code smell、duplication。Quality Gate 示例:新代码 coverage ≥ 80%、0 Blocker。ESLint/Prettier 在前端 PR 强制格式化——npm run lint 失败即不可 merge。
Checkstyle、SpotBugs 是 Java 静态分析补充;golangci-lint 聚合 Go 多种 linter。原则:能静态发现的不要留到运行时。
| 仓库 | 内容 | CI 动作 |
|---|---|---|
| maven-snapshots | 开发分支 SNAPSHOT | deploy on main |
| maven-releases | tag 版本 | deploy on tag v* |
| docker-hosted | 镜像 | push after build |
| pypi-hosted | Python wheel | twine upload |
制品保留策略:snapshot 30 天自动清理,release 永久——磁盘与合规的平衡。
开发者提交 → SCM Webhook → CI 拉代码 → 构建工具编译 → 测试框架执行 → 收集报告 → 成功则发布制品 → Slack/邮件通知 → 开发者修复或继续——九步闭环。任何一步失败,后续不执行(fail fast)。
没有治理流程的团队,最终会养成「重跑直到绿」的文化——quality gate 失效。
微服务间 API 契约由 consumer 定义、provider 验证——CI 阶段拦截 breaking change:
pact-broker can-i-deploy --pacticipant payment --version $GIT_SHA --to staging
比全链路 E2E 快一个数量级,适合 service mesh 架构。
第3章进入持续交付:制品如何在多环境管道中晋级。