Unit Testing
s# Unit Testing Guide
This guide explains how to run and write unit tests for the Tracker REST API.
Overview
The Tracker REST API uses pytest for unit testing. The tests are located in the tests directory and are organized as follows:
tests/conftest.py: Contains pytest fixtures used by the teststests/models.py: Contains SQLite-compatible models for testingtests/test_main.py: Tests for the main applicationtests/api/routes/: Tests for API routes
Running Tests
You can run tests either locally or in the Docker container.
Running Tests Locally
To run the tests locally, use the following command:
python -m pytest
To run a specific test file:
python -m pytest tests/test_main.py
To run tests with verbose output:
python -m pytest -v
Using Docker
To run the tests in the Docker container, use the following command:
docker exec tracker-restapi-dev-1 python -m pytest
To run a specific test file:
docker exec tracker-restapi-dev-1 python -m pytest tests/test_main.py
To run tests with verbose output:
docker exec tracker-restapi-dev-1 python -m pytest -v
Using the Docker Test Runner
We've created a custom test runner script that integrates with VSCode to run tests in the Docker container.
You can use the Docker test runner script directly:
.vscode/docker_test_runner.py tests/test_main.py
Or to run all tests:
.vscode/docker_test_runner.py tests
Using VSCode
You can run tests directly from VSCode using the integrated test explorer or the provided launch configurations. Our setup includes custom test runners that allow VSCode to run tests either locally or in the Docker container.
Using the Test Explorer
- Open the Test Explorer view by clicking on the flask icon in the sidebar
- You should see all the tests discovered in your project
- Click on the play button next to a test to run it
- You can also run all tests by clicking the play button at the top of the Test Explorer
The tests will run locally, and the results will be displayed in the Test Explorer.
Using Launch Configurations
- Open the test file you want to run
- Click on the "Run and Debug" icon in the sidebar
- Select one of the following configurations from the dropdown:
- "Python: Debug Tests" - Runs the current test file in the Docker container
- "Python: Debug All Tests" - Runs all tests in the Docker container
- "Python: Debug Tests in Docker" - Runs the current test file in the Docker container
- "Python: Debug Tests Locally" - Runs the current test file locally
- "Python: Debug All Tests Locally" - Runs all tests locally
- Click the green play button
Using Tasks
You can also run tests using the defined tasks:
- Press
Ctrl+Shift+P(orCmd+Shift+Pon macOS) to open the command palette - Type "Tasks: Run Task" and select it
- Choose one of the following tasks:
- "Run pytest in Docker" - Runs the current test file in the Docker container
- "Run all pytest in Docker" - Runs all tests in the Docker container
- "Run pytest locally" - Runs the current test file locally
- "Run all pytest locally" - Runs all tests locally
How It Works
Our VSCode integration uses custom test runner scripts that:
- Execute pytest either locally or in the Docker container
- Pass the appropriate test file or directory
- Display the results in VSCode
This allows you to use VSCode's test explorer and debugging features while running tests either locally or in the Docker container.
Test Database
The tests use SQLite as the database backend instead of PostgreSQL. This makes the tests faster and easier to run without requiring a PostgreSQL server.
The test database is created and destroyed for each test function, ensuring that tests don't interfere with each other.
SQLite Compatibility
Since the application uses PostgreSQL-specific features like the geography type, we need to use SQLite-compatible models for testing. These models are defined in tests/models.py.
Test Fixtures
The test fixtures are defined in tests/conftest.py. These fixtures provide the test environment and test data for the tests.
Key Fixtures
db: Provides a fresh database session for each testapp: Creates a FastAPI test applicationclient: Creates a TestClient for making HTTP requests to the APIadmin_user: Creates an admin user for testingregular_user: Creates a regular user for testingadmin_tokenanduser_token: Create authentication tokens for the admin and regular usersadmin_headersanduser_headers: Create headers with authentication tokens for making authenticated requeststest_client: Creates a test client (organization)test_brand: Creates a test brandtest_production_run: Creates a test production runtest_tracker: Creates a test tracker
Writing Tests
When writing tests, follow these guidelines:
- Use the provided fixtures to set up the test environment
- Test both successful and error cases
- Test with both admin and regular users to ensure proper authorization
- Use descriptive test names and docstrings
Example Test
def test_read_trackers(client: TestClient, admin_headers: dict, test_tracker: Tracker) -> None:
"""
Test retrieving a list of trackers.
"""
response = client.get("/api/v1/trackers/", headers=admin_headers)
assert response.status_code == 200
data = response.json()
assert "items" in data
assert "total" in data
assert data["total"] >= 1
Client Filtering
The API uses client filtering to restrict access to data based on the user's client list. In the tests, we set up the admin and regular users with access to the test client, so they can access the test data.
Debugging Tests
If a test is failing, you can use the VSCode debugger to step through the test and see what's happening. Set breakpoints in the test file or in the application code to see the values of variables at different points in the execution.
Test Coverage
To run tests with coverage reporting:
docker exec tracker-restapi-dev-1 python -m pytest --cov=app
This will show the test coverage for the app directory.
Continuous Integration
The tests are run automatically in the CI/CD pipeline. If a test fails in the pipeline, it will prevent the code from being deployed.