Architecture¶
This section documents the architectural decisions and design of pytest-test-categories.
Topics¶
Design Documents¶
Design Philosophy¶
The core principles behind pytest-test-categories:
The “no escape hatches” philosophy for small tests
Why strict enforcement matters
Trade-offs and design decisions
Comparison with other approaches (pytest-socket, pyfakefs, freezegun)
Hexagonal Architecture¶
How the codebase is structured for testability:
Ports and adapters pattern explanation
How it applies to the timer system and all blockers
Benefits for testability (fast unit tests, separate integration tests)
Code structure walkthrough
Overview¶
pytest-test-categories follows hexagonal architecture (ports and adapters pattern) for testability and maintainability.
Core Principles¶
Separation of Concerns: Each module has a single responsibility
Dependency Inversion: Core logic depends on abstractions, not implementations
Testability: All components can be tested in isolation using test doubles
Architecture Diagram¶
+---------------------+
| pytest hooks |
| (plugin.py) |
+----------+----------+
|
+----------v----------+
| Services |
| - timing_validation |
| - distribution |
| - test_discovery |
+----------+----------+
|
+---------------------+---------------------+
| | |
+--------v--------+ +--------v--------+ +--------v--------+
| Ports | | Types | | Exceptions |
| (interfaces) | | (domain models) | | |
+-----------------+ +-----------------+ +-----------------+
|
+--------v--------+
| Adapters |
| - pytest |
| - network |
| - filesystem |
| - process |
| - database |
| - sleep |
| - timers |
+-----------------+
Key Components¶
Plugin Entry Point (plugin.py)¶
The main pytest plugin that:
Registers pytest hooks
Initializes plugin state
Coordinates between services and adapters
Acts as a thin orchestration layer (all business logic delegated to services)
Ports (Interfaces)¶
Abstract interfaces defining contracts:
Port |
Purpose |
Location |
|---|---|---|
|
Timer interface for measuring test duration |
|
|
Interface for network blocking |
|
|
Interface for filesystem blocking |
|
|
Interface for subprocess blocking |
|
|
Interface for database connection blocking |
|
|
Interface for sleep call blocking |
|
|
Abstract pytest.Item |
|
|
Terminal output |
|
|
Warning emission |
|
|
Plugin state access |
|
Adapters (Implementations)¶
Concrete implementations of ports:
Port |
Production Adapter |
Test Adapter |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Services¶
Business logic modules:
timing_validation: Validates test timing constraintsdistribution_validation: Validates test distributiontest_discovery: Discovers test sizes from markerstest_reporting: Generates test size reports
Types¶
Domain models:
TestSize: Enum of test size categories (SMALL, MEDIUM, LARGE, XLARGE)TimeLimit: Immutable time limit configurationDistributionStats: Test distribution statisticsTimerState: State machine states (READY, RUNNING, STOPPED)
Exceptions¶
Custom exception hierarchy:
TimingViolationError: Test exceeded time limitHermeticityViolationError: Test violated hermeticity (base class)NetworkAccessViolationError: Test made unauthorized network requestFilesystemAccessViolationError: Test made unauthorized filesystem accessSubprocessViolationError: Test attempted to spawn subprocessDatabaseViolationError: Test attempted database connectionSleepViolationError: Test called sleep function
Architecture Decision Records (ADRs)¶
ADRs document significant architectural decisions with their context, decision, and consequences.
Index of ADRs¶
ADR |
Title |
Status |
Summary |
|---|---|---|---|
Network Isolation |
Proposed |
Socket-level blocking for small tests, localhost-only for medium |
|
Filesystem Isolation |
Proposed |
Comprehensive patching of file operations, tmp_path allowlisting |
|
Process Isolation |
Implemented |
Subprocess/os patching to block process spawning |
|
Database Isolation |
Implemented |
Database library patching including sqlite3, psycopg2, etc. |
|
Sleep Isolation |
Accepted |
time.sleep and asyncio.sleep blocking for small tests |
ADR Status Meanings¶
Proposed: Design documented, implementation in progress
Accepted: Design approved, ready for implementation
Implemented: Fully implemented and released
Superseded: Replaced by a newer ADR
Deprecated: No longer recommended
Further Reading¶
Design Philosophy - Core principles and trade-offs
Hexagonal Architecture - Detailed pattern explanation
Alistair Cockburn’s Hexagonal Architecture - Original pattern description
Google’s Software Engineering at Google - Testing - Test size philosophy source