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

12 KiB

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}

# 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

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}

# 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:

def test_create_user_success():
def test_login_valid_credentials():
def test_import_csv_valid_format():

Error/Edge Case Tests:

def test_create_user_duplicate_email_fails():
def test_login_invalid_credentials_rejected():
def test_import_csv_malformed_data_raises_error():

Permission/Security Tests:

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:

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:

@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

Keep related tests in the same file:

# 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:

# 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

# 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:

# 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:

# 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.