MkDocs documentation integration
This commit is contained in:
383
docs/testing/test-naming-conventions.md
Normal file
383
docs/testing/test-naming-conventions.md
Normal file
@@ -0,0 +1,383 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user