Files
orion/docs/testing/test-naming-conventions.md

383 lines
12 KiB
Markdown

# Test Naming Conventions
This document outlines the naming conventions used in our test suite to ensure consistency, clarity, and maintainability across the project.
## Overview
Our test suite follows a hierarchical structure organized by test type and component, with clear naming patterns that make it easy to locate and understand test purposes.
## Directory Structure
```
tests/
├── conftest.py # Core test configuration and fixtures
├── pytest.ini # Pytest configuration
├── fixtures/ # Shared test fixtures organized by domain
├── unit/ # Fast, isolated component tests
├── integration/ # Multi-component interaction tests
├── performance/ # Performance and load tests
├── system/ # End-to-end system behavior tests
└── test_data/ # Test data files (CSV, JSON, etc.)
```
## File Naming Conventions
### General Rule
All test files must start with `test_` prefix for pytest auto-discovery.
**Pattern:** `test_{component/feature}.py`
### Unit Tests (`tests/unit/`)
Focus on testing individual components in isolation.
```
tests/unit/
├── models/
│ ├── test_database_models.py # Database model tests
│ ├── test_api_models.py # API model validation
│ └── test_model_relationships.py # Model relationship tests
├── utils/
│ ├── test_data_processing.py # Data processing utilities
│ ├── test_csv_processor.py # CSV processing utilities
│ ├── test_validators.py # Validation utilities
│ └── test_formatters.py # Data formatting utilities
├── services/
│ ├── test_admin_service.py # Admin service business logic
│ ├── test_auth_service.py # Authentication service
│ ├── test_product_service.py # Product management service
│ ├── test_shop_service.py # Shop management service
│ ├── test_stock_service.py # Stock management service
│ ├── test_marketplace_service.py # Marketplace import service
│ └── test_stats_service.py # Statistics service
└── core/
├── test_config.py # Configuration management
├── test_database.py # Database utilities
└── test_logging.py # Logging functionality
```
### Integration Tests (`tests/integration/`)
Focus on testing interactions between multiple components.
```
tests/integration/
├── api/v1/
│ ├── test_auth_endpoints.py # Authentication API endpoints
│ ├── test_admin_endpoints.py # Admin API endpoints
│ ├── test_product_endpoints.py # Product CRUD endpoints
│ ├── test_shop_endpoints.py # Shop management endpoints
│ ├── test_stock_endpoints.py # Stock management endpoints
│ ├── test_marketplace_endpoints.py # Import endpoints
│ ├── test_stats_endpoints.py # Statistics endpoints
│ └── test_pagination.py # Pagination functionality
├── database/
│ ├── test_migrations.py # Database migration tests
│ ├── test_transactions.py # Transaction handling
│ └── test_constraints.py # Database constraints
├── security/
│ ├── test_authentication.py # Authentication mechanisms
│ ├── test_authorization.py # Permission and role tests
│ ├── test_input_validation.py # Input security validation
│ ├── test_rate_limiting.py # Rate limiting middleware
│ └── test_cors.py # CORS configuration
└── workflows/
├── test_product_import_workflow.py # Complete import process
├── test_user_registration_flow.py # User registration process
└── test_shop_setup_flow.py # Shop creation workflow
```
### System Tests (`tests/system/`)
Focus on end-to-end application behavior.
```
tests/system/
├── test_application_startup.py # Application initialization
├── test_error_handling.py # Global error handling
├── test_health_checks.py # Health endpoint tests
├── test_database_connectivity.py # Database connection tests
└── test_external_dependencies.py # Third-party service tests
```
### Performance Tests (`tests/performance/`)
Focus on performance benchmarks and load testing.
```
tests/performance/
├── test_api_performance.py # API endpoint performance
├── test_database_performance.py # Database query performance
├── test_import_performance.py # Large file import tests
└── test_concurrent_users.py # Multi-user scenarios
```
## Class Naming Conventions
Use descriptive class names that clearly indicate what is being tested:
### Pattern: `Test{ComponentName}{TestType}`
```python
# Good examples
class TestProductService: # Testing ProductService class
class TestProductModel: # Testing Product model
class TestProductEndpoints: # Testing product API endpoints
class TestProductValidation: # Testing product validation logic
class TestProductPermissions: # Testing product access control
# Avoid generic names
class TestProduct: # Too vague - what aspect of Product?
class Tests: # Too generic
```
### Specialized Class Naming
```python
class TestProductCRUD: # CRUD operations
class TestProductSecurity: # Security-related tests
class TestProductErrorHandling: # Error scenario tests
class TestProductEdgeCases: # Boundary condition tests
```
## Method Naming Conventions
Test method names should be descriptive and follow a clear pattern that explains:
1. What is being tested
2. The scenario/condition
3. Expected outcome
### Pattern: `test_{action}_{scenario}_{expected_outcome}`
```python
# Good examples - Clear and descriptive
def test_create_product_with_valid_data_returns_product():
def test_create_product_with_invalid_gtin_raises_validation_error():
def test_get_product_by_id_when_not_found_returns_404():
def test_update_product_without_permission_raises_forbidden():
def test_delete_product_with_existing_stock_prevents_deletion():
# Acceptable shorter versions
def test_create_product_success():
def test_create_product_invalid_data():
def test_create_product_unauthorized():
def test_get_product_not_found():
```
### Method Naming Patterns by Scenario
**Happy Path Tests:**
```python
def test_create_user_success():
def test_login_valid_credentials():
def test_import_csv_valid_format():
```
**Error/Edge Case Tests:**
```python
def test_create_user_duplicate_email_fails():
def test_login_invalid_credentials_rejected():
def test_import_csv_malformed_data_raises_error():
```
**Permission/Security Tests:**
```python
def test_admin_endpoint_requires_admin_role():
def test_user_cannot_access_other_user_data():
def test_api_key_required_for_marketplace_import():
```
**Boundary/Edge Cases:**
```python
def test_pagination_with_zero_items():
def test_price_with_maximum_decimal_places():
def test_gtin_with_minimum_valid_length():
```
## Marker Usage
Use pytest markers to categorize and run specific test types:
```python
@pytest.mark.unit
class TestProductService:
"""Unit tests for ProductService business logic"""
@pytest.mark.integration
@pytest.mark.api
class TestProductEndpoints:
"""Integration tests for Product API endpoints"""
@pytest.mark.slow
@pytest.mark.performance
class TestImportPerformance:
"""Performance tests for large CSV imports"""
```
### Available Markers
| Marker | Purpose |
|--------|---------|
| `@pytest.mark.unit` | Fast, isolated component tests |
| `@pytest.mark.integration` | Multi-component interaction tests |
| `@pytest.mark.system` | End-to-end system tests |
| `@pytest.mark.performance` | Performance and load tests |
| `@pytest.mark.slow` | Long-running tests |
| `@pytest.mark.api` | API endpoint tests |
| `@pytest.mark.database` | Tests requiring database |
| `@pytest.mark.auth` | Authentication/authorization tests |
| `@pytest.mark.admin` | Admin functionality tests |
## File Organization Best Practices
### Mirror Source Structure
Test files should mirror the source code structure:
```
app/services/product_service.py → tests/unit/services/test_product_service.py
app/api/v1/admin.py → tests/integration/api/v1/test_admin_endpoints.py
```
### Group Related Tests
Keep related tests in the same file:
```python
# test_product_service.py
class TestProductCreation: # All product creation scenarios
class TestProductValidation: # All validation scenarios
class TestProductQueries: # All query scenarios
```
### Separate Complex Workflows
Break complex workflows into separate files:
```
test_user_registration_flow.py # Complete registration process
test_shop_setup_flow.py # Shop creation workflow
test_product_import_workflow.py # CSV import end-to-end
```
## Running Tests by Name Pattern
Use pytest's flexible test discovery:
```bash
# Run all unit tests
pytest tests/unit/ -v
# Run specific component tests
pytest tests/ -k "product" -v
# Run by marker
pytest -m "unit and not slow" -v
# Run specific test class
pytest tests/unit/services/test_product_service.py::TestProductService -v
# Run specific test method
pytest tests/unit/services/test_product_service.py::TestProductService::test_create_product_success -v
```
## Examples
### Complete Test File Example
```python
# tests/unit/services/test_product_service.py
import pytest
from unittest.mock import Mock, patch
from app.services.product_service import ProductService
from app.models.database_models import Product
@pytest.mark.unit
class TestProductService:
"""Unit tests for ProductService business logic"""
def setup_method(self):
"""Setup run before each test method"""
self.service = ProductService()
self.mock_db = Mock()
def test_create_product_with_valid_data_returns_product(self):
"""Test successful product creation with valid input data"""
# Arrange
product_data = {
"name": "Test Product",
"gtin": "1234567890123",
"price": "19.99"
}
# Act
result = self.service.create_product(product_data)
# Assert
assert result is not None
assert result.name == "Test Product"
def test_create_product_with_invalid_gtin_raises_validation_error(self):
"""Test product creation fails with invalid GTIN format"""
# Arrange
product_data = {
"name": "Test Product",
"gtin": "invalid_gtin",
"price": "19.99"
}
# Act & Assert
with pytest.raises(ValidationError, match="Invalid GTIN format"):
self.service.create_product(product_data)
@pytest.mark.unit
class TestProductValidation:
"""Unit tests for product validation logic"""
def test_validate_gtin_with_valid_format_returns_true(self):
"""Test GTIN validation accepts valid 13-digit GTIN"""
assert ProductService.validate_gtin("1234567890123") is True
def test_validate_gtin_with_invalid_format_returns_false(self):
"""Test GTIN validation rejects invalid format"""
assert ProductService.validate_gtin("invalid") is False
```
## Naming Anti-Patterns to Avoid
**Avoid these patterns:**
```python
# Too generic
def test_product():
def test_user():
def test_api():
# Unclear purpose
def test_function():
def test_method():
def test_endpoint():
# Non-descriptive
def test_1():
def test_a():
def test_scenario():
# Inconsistent naming
def testProductCreation(): # Wrong case
def test_product_creation(): # Good
def TestProductCreation(): # Wrong - this is for classes
```
**Use these patterns instead:**
```python
# Clear, descriptive, consistent
def test_create_product_with_valid_data_succeeds():
def test_authenticate_user_with_invalid_token_fails():
def test_get_products_endpoint_returns_paginated_results():
```
---
Following these naming conventions will help maintain a clean, understandable, and maintainable test suite that scales with your project.