如何通过GitHub Actions将PR中的Python文件传入pytest执行测试
解决GitHub Action中仅测试PR变更Python文件的问题
问题场景
在GitHub Action中,想要仅对PR里变更的Python文件执行pytest测试,而非全目录运行。当前Action脚本通过tj-actions/changed-files获取变更文件,循环执行pytest时出现如下错误:
Testing Lessons/Intro-to-Python/1/Activities/01-Ins_Python_Intro/Solved/variables_solution.py ======================== test session starts ========================= platform linux -- Python 3.10.13, pytest-8.0.1, pluggy-1.4.0 rootdir: /home/runner/work/GitHub-Actions-Playground/GitHub-Actions-Playground collected 0 items ===================== no tests ran in 0.01s ======================= Error: Process completed with exit code 5.
核心原因
- 退出码5的含义:pytest的退出码5表示未找到任何可执行的测试用例。你执行的
variables_solution.py是业务代码文件,本身不包含pytest可识别的测试用例(pytest默认识别test_*.py或*_test.py命名的文件,以及文件内test_开头的函数/类)。 - 循环执行的缺陷:当前脚本对每个变更的Python文件单独执行
pytest,只要有一个文件无测试用例,就会直接触发错误终止整个Action,后续文件无法执行。 - 文件名处理风险:直接用
for file in ${{ steps.changed-files.outputs.all_changed_files }}遍历,会把带空格的文件名拆分成多个元素,导致路径错误。
解决方案
方案1:仅测试变更的测试文件
如果目标是跑PR中修改的测试文件,可直接筛选符合pytest命名规则的文件,批量执行:
修改Action的changed-files步骤和测试步骤:
jobs: build: name: Testing Python Files runs-on: ubuntu-latest permissions: contents: read pull-requests: read steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Get changed test Python files id: changed-test-files uses: tj-actions/changed-files@v42 with: since_last_remote_commit: true # 只筛选符合pytest命名规则的测试文件 files: | **/test_*.py **/*_test.py - name: Set up Python 3.10 uses: actions/setup-python@v5 with: python-version: "3.10" - name: Install dependencies run: | python -m pip install --upgrade pip pip install pytest - name: Run pytest on changed test files run: | CHANGED_TESTS="${{ steps.changed-test-files.outputs.all_changed_files }}" if [ -z "$CHANGED_TESTS" ]; then echo "No changed test files to run." exit 0 fi # 处理带空格的文件名,转成数组 readarray -t TEST_FILES <<< "$CHANGED_TESTS" pytest "${TEST_FILES[@]}"
方案2:针对变更的业务文件,关联执行对应的测试文件
如果要测试变更业务代码对应的测试用例(比如业务文件variables_solution.py对应测试文件test_variables_solution.py),可以通过文件名关联找到测试文件再执行:
修改测试步骤:
- name: Testing Python files run: | # 获取所有变更的Python文件 CHANGED_PY_FILES="${{ steps.changed-files.outputs.all_changed_files }}" if [ -z "$CHANGED_PY_FILES" ]; then echo "No changed Python files to test." exit 0 fi readarray -t PY_FILES <<< "$CHANGED_PY_FILES" TEST_FILES=() for file in "${PY_FILES[@]}"; do # 跳过本身就是测试文件的情况(如果需要的话) if [[ $file == test_*.py || $file == *_test.py ]]; then TEST_FILES+=("$file") continue fi # 生成对应的测试文件名(假设测试文件命名为test_xxx.py) TEST_FILE=$(echo "$file" | sed 's/\(.*\)\.py/test_\1.py/') # 如果测试文件存在,加入列表 if [ -f "$TEST_FILE" ]; then TEST_FILES+=("$TEST_FILE") fi done if [ ${#TEST_FILES[@]} -eq 0 ]; then echo "No related test files found for changed Python files." exit 0 fi echo "Running tests for: ${TEST_FILES[*]}" pytest "${TEST_FILES[@]}"
方案3:允许无测试用例的文件,避免Action失败
如果希望即使变更文件无测试用例,Action也不失败,可以给单个pytest命令添加容错处理(不推荐,可能掩盖真实测试错误):
for file in "${PY_FILES[@]}"; do if [[ $file == *.py ]]; then echo "Testing $file" # 仅忽略无测试用例的错误,其他错误正常抛出 pytest $file || if [ $? -eq 5 ]; then echo "No tests found in $file"; else exit 1; fi fi done
内容的提问来源于stack exchange,提问作者AtxTom
相关产品推荐
相关产品推荐

