用 GitHub Actions 定时运行后端集成测试并保存报告
最近给后端仓库补了一些集成测试,本地跑着倒是没问题,但问题是你不可能每天都记得去跑一遍。尤其是那种依赖数据库、缓存、第三方接口 mock 的测试,平时单元测试根本覆盖不到。后来我索性把这件事丢给 GitHub Actions,让它每天定时跑一次,跑完把报告存下来。踩了几个小坑,这里记录一下,免得下次又翻车。
先想清楚要跑什么
我一开始图省事,直接把整个测试套件都塞进定时任务里,结果每次跑二十多分钟,报告里还混着一堆单元测试,看着很乱。后来改成只跑带 integration 标记的用例,单元测试还是留在提交时跑。
命令大概是这样:
pytest -m integration -ra --junitxml=reports/integration.xml --html=reports/integration.html --self-contained-html
这里顺手装了 pytest-html,因为 JUnit XML 虽然很多工具都能解析,但人看着确实不太直观。HTML 报告丢到 artifact 里,点开就能看哪条用例挂了、堆栈是什么。--self-contained-html 也别省,不然 CSS 和图片是外链,下载下来容易缺东西。
准备数据库这些依赖
集成测试一般离不开数据库。GitHub Actions 里可以用 services 起一个 PostgreSQL,没必要去连外部环境。我现在的写法大概是这样:
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: app_test
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U test -d app_test"
--health-interval 5s
--health-timeout 5s
--health-retries 10
这个 health check 挺重要的,不然数据库还没起来,测试已经开始连了,然后就是一堆连接失败。虽然可以在测试前自己写个等待循环,但能让 service 自己报告健康状态就省事很多。
如果项目还依赖 Redis、MinIO 之类的,也可以照这个思路继续加 service。端口映射到 runner 的 localhost,测试配置里直接用就行。
写 workflow 文件
workflow 放在 .github/workflows/nightly-integration.yml,名字随便取,我这边叫 Nightly Integration Tests。
name: Nightly Integration Tests
on:
schedule:
- cron: '0 18 * * *'
workflow_dispatch:
jobs:
integration:
runs-on: ubuntu-latest
timeout-minutes: 30
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: app_test
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U test -d app_test"
--health-interval 5s
--health-timeout 5s
--health-retries 10
env:
DATABASE_URL: postgresql://test:test@localhost:5432/app_test
APP_ENV: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: pip
- name: Install dependencies
run: |
python -m pip install -U pip
pip install -r requirements.txt
pip install pytest pytest-html
- name: Prepare database
run: |
# 这里换成你项目自己的迁移或建表命令
# 比如 python manage.py migrate --noinput
echo "prepare database"
- name: Run integration tests
run: |
mkdir -p reports
pytest -m integration -ra \
--junitxml=reports/integration.xml \
--html=reports/integration.html \
--self-contained-html
- name: Upload test report
if: always()
uses: actions/upload-artifact@v4
with:
name: integration-report
path: reports/
retention-days: 14
这里有几个地方我觉得值得说一下。
第一,workflow_dispatch 最好加上。定时任务出问题的时候,你可以手动点一次跑,不用等第二天。调试 workflow 的时候特别有用。
第二,if: always() 一定要加在 upload-artifact 上。我一开始没加,结果测试失败的时候,后面上传报告那一步直接跳过了,artifacts 里空空如也。后来才反应过来,测试失败时默认后续 step 不执行,必须用 always() 才能把失败报告也存下来。这个坑挺蠢的,但确实容易忘。
第三,mkdir -p reports 别省。虽然 pytest 生成报告时会自己建目录,但如果你中间加了别的命令,或者路径写错,先建目录能少排查一点。
定时任务和时区
GitHub Actions 的 cron 用的是 UTC,不是北京时间。我上面写的 0 18 * * *,实际是北京时间第二天凌晨 2 点。如果你想每天早上 9 点跑,那大概得写 0 1 * * *。这个换算第一次看容易懵,建议直接在 workflow 里写注释,不然后面自己都忘了。
另外,schedule 只会在默认分支上生效。你在功能分支里改 cron,不合并到默认分支是不会按新时间跑的。还有就是 GitHub 的定时任务不保证完全准时,忙的时候延迟几分钟甚至更久都正常,所以别拿它当特别精确的闹钟用。
报告保存和失败排查
现在每次跑完,Actions 页面里会有一个 integration-report 的 artifact,里面包含 integration.xml 和 integration.html。我一般先看 HTML,挂了哪条用例、错误堆栈、截图之类的一眼就能看到。XML 可以留着给以后接测试报告平台用,虽然目前我还没接。
如果测试失败,除了报告,Actions 日志里也能看到 pytest 的输出。我习惯在本地先跑一遍同样的命令,确认是不是环境问题。很多时候不是代码挂了,而是数据库迁移没跑、环境变量没配、或者测试依赖的外部服务地址写死了。定时任务的好处是它每天都用一套干净环境跑,反而更容易暴露这些问题。
还有一点,私有仓库跑 Actions 会消耗额度,定时任务别设得太频繁。一天一次或者工作日每天一次就够了。报告保留天数也没必要设太长,我设的是 14 天,出问题的时候够翻就行。
这套东西跑起来之后,至少不用靠人记得去点测试了。哪天数据库升级、依赖版本变化、或者某个接口悄悄改了行为,第二天的报告里基本都能看出来。省事是真省事,前提是把 if: always() 和时区这两个坑先填上。
评论
还没有评论。
发表评论
提交后评论将经过自动审核,审核通过后公开展示。