How to Run Python unittest Tests in GitHub Actions
To run Python tests in GitHub Actions, add a job that checks out the code and runs python -m unittest discover against your tests folder. Most broken test jobs have one wrong value: the start directory, the top-level directory, or the working directory. Run the job locally with act to see the error in seconds.
A minimal test workflow
Given this layout:
.
├── app.py
├── tests/
│ ├── __init__.py
│ └── test_app.py
└── .github/workflows/ci.yaml
The workflow:
# .github/workflows/ci.yaml
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Run unit tests
run: python -m unittest discover -s tests -t . -v
What the unittest discover flags mean
-s tests- the start directory. unittest searches here for test files.-t .- the top-level directory. It is added to the import path, sofrom app import addinside a test resolves to./app.py.-p 'test*.py'- the file name pattern.test*.pyis the default.-v- verbose output: one line per test.
If -s points at a folder that does not exist, unittest fails with an error
like ImportError: Start directory is not importable: 'app_tests'. The job
fails, but the code and tests are fine - only the path in the workflow is wrong.
Step 1: read the failing step
In the GitHub Actions UI, open the failed run, then the test job, then the
red step. The last lines show the error. Compare the path in the error with
your repository:
ls
cat .github/workflows/ci.yaml
Step 2: run the job locally with act
Pushing a commit for every attempt is slow. act runs GitHub Actions workflows on your own machine in containers:
act push -j test
-j test runs only the test job. You see the same step output as on GitHub,
in a few seconds.
Step 3: correct the path and run again
- name: Run unit tests
run: python -m unittest discover -s tests -t .
act push -j test
A passing run ends with output like this:
Ran 2 tests in 0.001s
OK
Job succeeded
Watch out for "Ran 0 tests"
A job can be green and still test nothing. If discovery finds no files, recent Python versions exit with a non-zero code, but older versions and some other runners report success. Check the log for the number of tests. Common reasons for zero tests:
- Test files do not match the pattern (
app_test.pydoes not matchtest*.py). - The tests folder has no
__init__.pyand your layout needs it. - Test methods do not start with
test.
A simple guard is to look for the count in the output, or to use a coverage tool with a minimum threshold, so "ran nothing" fails the build.
Using pytest instead
pytest also runs unittest-style tests:
- run: pip install pytest
- run: pytest tests/ -v
pytest exits with code 5 when it collects no tests, so an empty run fails the job by default.
Other common causes of a failing test job
- Working directory - the tests live in a subfolder. Add
working-directory: backendto the step. - Missing dependencies - add
pip install -r requirements.txtbefore the test step. - Wrong Python version - set
python-versionwithactions/setup-python. - Wrong branch filter -
on.push.branchesdoes not include the branch you pushed to, so the job never runs.
Do this project yourself. It's ready in a live cloud workspace in your browser - when you finish, it lands on your portfolio.
Start this project - freeWhat you'll practice
- Writing a GitHub Actions job that runs python -m unittest discover
- Running a single workflow job locally with act push -j test
- Correcting a wrong test directory path in a workflow step
FAQ
How do I run Python unit tests in GitHub Actions?
Add a job with actions/checkout, optionally actions/setup-python, and a step that runs python -m unittest discover -s tests -t .. Every push then runs your tests.
What does 'Start directory is not importable' mean?
The folder passed to unittest discover -s does not exist or is not a Python package. Check the path against your repository layout.
How can I test a GitHub Actions workflow locally?
Use act. act push -j test runs the test job for a push event on your machine, using containers, without pushing to GitHub.
Why does my CI job pass but run 0 tests?
Test discovery found no files - usually a wrong start directory or a file name that does not match test*.py. Check the test count in the log and make an empty run fail the build.
Keep learning
Do this project yourself. It's ready in a live cloud workspace in your browser - when you finish, it lands on your portfolio.
Start this project - free