Tests¶
This document outlines the testing procedures for the Aipress24 project. We use a combination of unit, integration, and end-to-end tests to ensure code quality and reliability.
Test organisation (tiers)¶
Python tests live under tests/ and are split into three tiers, run in order and increasingly close to a real environment:
tests/a_unit— fast, isolated unit tests. Thedb_sessionfixture yieldsNone: these tests do not touch a database.tests/b_integration— integration tests running inside a savepoint (nested transaction) that is rolled back after each test, so they share a fast, always-clean database without committing.tests/c_e2e— end-to-end tests using a committing Flask test client against a fresh (drop/create) in-memory database (thefresh_db/logged_in_client/make_authenticated_clientfixtures). These exercise real request → commit → teardown behaviour.
Tests must clean up after themselves: a tier must leave the database in the state the next tier expects.
The suite runs against both SQLite (default, fast) and PostgreSQL — see make test-sqlite / make test-postgres.
Browser-based end-to-end tests (Playwright) live under e2e_playwright/ and run against a running server (see below).
Prerequisites¶
Before running tests, ensure you have installed the necessary dependencies, including testing tools, as described in the Getting Started / Installation section of the README. This typically involves running:
Running Tests¶
The Makefile provides convenient shortcuts for various testing tasks. You can view all available testing commands by running:
Here’s a breakdown of the most common testing scenarios:
Unit and Integration Tests¶
These tests are executed using pytest and cover individual components (unit tests) and their interactions (integration tests).
-
Run all tests (unit and integration):
or
-
Run tests in random order (helps detect order-dependent issues):
-
Run tests with coverage report:
or
-
Run tests with runtime type checking (using
typeguard):
or
-
Run tests with runtime type checking (using
beartype):
or
Linting and Static Analysis¶
Before running tests, it’s highly recommended to run linters and static analysis to catch potential issues early.
or:
End-to-End Tests¶
End-to-end tests simulate user interactions with the application and verify that the entire system works as expected.
More information in the tests-e2e directory.
Nox Integration Tests¶
Nox is a powerful tool for automating tests in multiple environments. It uses a noxfile.py configuration file to define various testing sessions.
Nox sessions are shown by nox -l:
test-3.12,test-3.11,test-3.10: These sessions run the test suite (usingpytest) against Python 3.12, 3.11 and 3.10 respectively. This ensures that the code is compatible with different Python versions.lint: This session runs linters and static analysis tools (e.g.,ruff,mypy) to check code quality and catch potential errors, as configured in thenoxfile.pycheck_prod: This session checks the code for production readiness.
To run a specific Nox session, use nox -s <session_name>. For example:
Running nox without the -s flag will execute all sessions marked with a star * by default, in this case the tests against all supported Python versions.
Continuous Integration¶
CI runs primarily on GitHub Actions (.github/workflows/):
ci.yml/tests.yml— run the test suite and checks on every push / pull request.lint.yml— runs the lint and static-analysis gates (ruff, type checkers, import-linting…).fly-deploy.yml— deploys the application to Fly.io.
Historically, SourceHut builds (.builds/) were also used, generated from a GitHub mirror. The use of uv and nox in CI mirrors the recommended local development and testing workflow.
Notes¶
- The
Makefileshortcuts are recommended for ease of use and consistency. - Ensure your development environment is properly set up before running tests (see the “Development Environment” section in the README).
- When contributing code, please make sure to add appropriate unit and integration tests to cover your changes.