GitHub Actions · pytest

When pytest exits 5 with no tests collected.

Exit code 5 does not mean a test assertion failed. It means pytest collected no tests. In CI, start with the runner's actual directory and collection rules instead of turning the exit code into success.

============================ no tests ran ============================
Error: Process completed with exit code 5.

Short version: run python -m pytest --collect-only against the intended test directory, confirm the pytest command runs from the intended package directory, then fix the path, naming convention, or selection filter that removed every test.

Collection starts from a real directory.

Repository root

Without an explicit argument, pytest starts from configured testpaths or the current directory. That may be correct in a single-package repository.

Monorepo package

A service under services/api usually needs an explicit test path or a run-step working-directory. Checkout does not choose the package for later commands.

A job that makes collection explicit.

jobs:
  test-api:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: services/api
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-python@v7
        with:
          python-version: "3.13"
          cache: pip
          cache-dependency-path: services/api/requirements.txt
      - run: python -m pip install -r requirements.txt
      - name: Show collected tests
        run: python -m pytest --collect-only -q tests
      - name: Run tests
        run: python -m pytest -q tests

The working directory applies to each run step. The setup action still receives a repository-relative dependency path. The temporary collection step makes a zero-test boundary visible before the full test command.

Check these in order.

  1. Print the intended package directory and verify the test tree was checked out at the expected case-sensitive path.
  2. Run python -m pytest --collect-only -q tests from the same directory and with the same configuration as CI.
  3. Check testpaths, norecursedirs, and custom python_files, python_classes, or python_functions settings.
  4. Under pytest's defaults, use test_*.py or *_test.py modules, test-prefixed functions, and Test-prefixed classes without an __init__ method.
  5. Remove -k, marker, node-id, or path filters temporarily and confirm they did not select an empty set.

Three tempting non-fixes.

Boundary: successful collection proves pytest found test items. It does not prove those tests exercise the intended package, use the expected installed code, or will pass.

Primary references.

Diagnose before you buy.

Run the free offline CI Rescue Action against one workflow and an optional sanitized log. If the report still leaves the hosted failure unresolved, request a focused diagnosis, reviewable patch, and verification report for one failing job path.

Run the free diagnostic → Request a $49 rescue →