major-domo-v2/tests
Cal Corum 3c66ada99d CLAUDE: Add pagination and move ID display to /mymoves command
- Fix transaction count bug by filtering transactions >= current week
- Add TransactionPaginationView with "Show Move IDs" button
- Implement intelligent message chunking for long transaction lists
- Remove emojis from individual transaction lines (kept in headers)
- Display 10 transactions per page with navigation buttons
- Show move IDs on demand via ephemeral button (stays under 2000 char limit)
- Update all tests to validate pagination and chunking behavior

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-14 16:51:24 -05:00
..
__init__.py CLAUDE: Initial commit for discord-app-v2 rebuild 2025-08-15 00:04:50 -05:00
factories.py CLAUDE: Add weather and charts commands with utility infrastructure 2025-10-10 09:59:49 -05:00
README.md CLAUDE: Add weather and charts commands with utility infrastructure 2025-10-10 09:59:49 -05:00
test_api_client.py CLAUDE: SUCCESSFUL STARTUP - Discord Bot v2.0 fully operational 2025-08-16 07:36:47 -05:00
test_commands_charts.py CLAUDE: Add weather and charts commands with utility infrastructure 2025-10-10 09:59:49 -05:00
test_commands_dice.py CLAUDE: Refactor dice roll functions to use DiceRoll dataclass 2025-10-14 14:28:19 -05:00
test_commands_dropadd.py CLAUDE: Fix trade system issues and enhance documentation 2025-10-06 16:10:13 -05:00
test_commands_profile_images.py CLAUDE: Implement player image management system 2025-10-10 13:54:12 -05:00
test_commands_soak.py CLAUDE: Implement soak easter egg with disappointment GIFs and tracking 2025-10-13 23:25:22 -05:00
test_commands_transactions.py CLAUDE: Add pagination and move ID display to /mymoves command 2025-10-14 16:51:24 -05:00
test_commands_voice.py CLAUDE: Comprehensive bot improvements and test infrastructure 2025-10-02 11:35:26 -05:00
test_commands_weather.py CLAUDE: Add weather and charts commands with utility infrastructure 2025-10-10 09:59:49 -05:00
test_config.py CLAUDE: Major bot enhancements - Admin commands, player stats, standings, schedules 2025-08-28 15:32:38 -05:00
test_constants.py CLAUDE: Initial commit for discord-app-v2 rebuild 2025-08-15 00:04:50 -05:00
test_dropadd_integration.py CLAUDE: Comprehensive bot improvements and test infrastructure 2025-10-02 11:35:26 -05:00
test_exceptions.py CLAUDE: Initial commit for discord-app-v2 rebuild 2025-08-15 00:04:50 -05:00
test_models_custom_command.py CLAUDE: Major bot enhancements - Admin commands, player stats, standings, schedules 2025-08-28 15:32:38 -05:00
test_models_help_command.py CLAUDE: Add graceful error handling for missing creators in custom commands 2025-10-13 17:53:58 -05:00
test_models_trade.py CLAUDE: Fix trade system issues and enhance documentation 2025-10-06 16:10:13 -05:00
test_models_transaction.py CLAUDE: Complete dice command system with fielding mechanics 2025-09-24 22:30:31 -05:00
test_models.py CLAUDE: Add logged_command decorator and migrate Discord commands to reduce boilerplate 2025-08-15 14:56:42 -05:00
test_services_base_service.py CLAUDE: Major bot enhancements - Admin commands, player stats, standings, schedules 2025-08-28 15:32:38 -05:00
test_services_custom_commands.py CLAUDE: Major bot enhancements - Admin commands, player stats, standings, schedules 2025-08-28 15:32:38 -05:00
test_services_help_commands.py CLAUDE: Add graceful error handling for missing creators in custom commands 2025-10-13 17:53:58 -05:00
test_services_integration.py CLAUDE: Initial commit for discord-app-v2 rebuild 2025-08-15 00:04:50 -05:00
test_services_league_service.py CLAUDE: Add logged_command decorator and migrate Discord commands to reduce boilerplate 2025-08-15 14:56:42 -05:00
test_services_player_service.py CLAUDE: Comprehensive bot improvements and test infrastructure 2025-10-02 11:35:26 -05:00
test_services_team_service.py CLAUDE: Fix trade system issues and enhance documentation 2025-10-06 16:10:13 -05:00
test_services_trade_builder.py CLAUDE: Fix trade system bugs and add smart channel updates 2025-10-09 20:55:19 -05:00
test_services_transaction_builder.py CLAUDE: Comprehensive bot improvements and test infrastructure 2025-10-02 11:35:26 -05:00
test_services_transaction.py CLAUDE: Complete dice command system with fielding mechanics 2025-09-24 22:30:31 -05:00
test_tasks_custom_command_cleanup.py CLAUDE: Major bot enhancements - Admin commands, player stats, standings, schedules 2025-08-28 15:32:38 -05:00
test_transactions_integration.py CLAUDE: Comprehensive bot improvements and test infrastructure 2025-10-02 11:35:26 -05:00
test_utils_autocomplete.py CLAUDE: Fix trade system issues and enhance documentation 2025-10-06 16:10:13 -05:00
test_utils_decorators.py CLAUDE: Add logged_command decorator and migrate Discord commands to reduce boilerplate 2025-08-15 14:56:42 -05:00
test_utils_logging.py CLAUDE: SUCCESSFUL STARTUP - Discord Bot v2.0 fully operational 2025-08-16 07:36:47 -05:00
test_views_custom_commands.py CLAUDE: Major bot enhancements - Admin commands, player stats, standings, schedules 2025-08-28 15:32:38 -05:00
test_views_transaction_embed.py CLAUDE: Comprehensive bot improvements and test infrastructure 2025-10-02 11:35:26 -05:00
TRANSACTION_TEST_COVERAGE.md CLAUDE: Complete dice command system with fielding mechanics 2025-09-24 22:30:31 -05:00

Testing Guide for Discord Bot v2.0

This document provides guidance on testing strategies, patterns, and lessons learned during the development of the Discord Bot v2.0 test suite.

Test Structure Overview

tests/
├── README.md                           # This guide
├── __init__.py                        # Test package
├── fixtures/                          # Test data fixtures
├── test_config.py                     # Configuration tests
├── test_constants.py                  # Constants tests
├── test_exceptions.py                 # Exception handling tests
├── test_models.py                     # Pydantic model tests
├── test_services.py                   # Service layer tests (25 tests)
└── test_api_client_with_aioresponses.py   # API client HTTP tests (19 tests)

Total Coverage: 44 comprehensive tests covering all core functionality.

Key Testing Patterns

1. HTTP Testing with aioresponsesf

Recommended Approach:

from aioresponses import aioresponses

@pytest.mark.asyncio
async def test_api_request(api_client):
    with aioresponses() as m:
        m.get(
            "https://api.example.com/v3/players/1",
            payload={"id": 1, "name": "Test Player"},
            status=200
        )
        
        result = await api_client.get("players", object_id=1)
        assert result["name"] == "Test Player"

Avoid Complex AsyncMock: We initially tried mocking aiohttp's async context managers manually with AsyncMock, which led to complex, brittle tests that failed due to coroutine protocol issues.

2. Service Layer Testing

Complete Model Data: Always provide complete model data that satisfies Pydantic validation:

def create_player_data(self, player_id: int, name: str, **kwargs):
    """Create complete player data for testing."""
    base_data = {
        'id': player_id,
        'name': name,
        'wara': 2.5,                    # Required field
        'season': 12,                   # Required field
        'team_id': team_id,            # Required field
        'image': f'https://example.com/player{player_id}.jpg',  # Required field
        'pos_1': position,             # Required field
    }
    base_data.update(kwargs)
    return base_data

Partial Model Data: Providing incomplete data leads to Pydantic validation errors that are hard to debug.

3. API Response Format Testing

Our API returns responses in this format:

{
  "count": 25,
  "players": [...]
}

Test Both Formats:

# Test the count + list format
mock_data = {
    "count": 2,
    "players": [player1_data, player2_data]
}

# Test single object format (for get_by_id)
mock_data = player1_data

Lessons Learned

1. aiohttp Testing Complexity

Problem: Manually mocking aiohttp's async context managers is extremely complex and error-prone.

Solution: Use aioresponses library specifically designed for this purpose.

Code Example:

pip install aioresponses>=0.7.4
# Clean, readable, reliable
with aioresponses() as m:
    m.get("https://api.example.com/endpoint", payload=expected_data)
    result = await client.get("endpoint")

2. Pydantic Model Validation in Tests

Problem: Our models have many required fields. Partial test data causes validation errors.

Solution: Create helper functions that generate complete, valid model data.

Pattern:

def create_model_data(self, id: int, name: str, **overrides):
    """Create complete model data with all required fields."""
    base_data = {
        # All required fields with sensible defaults
        'id': id,
        'name': name,
        'required_field1': 'default_value',
        'required_field2': 42,
    }
    base_data.update(overrides)
    return base_data

3. Async Context Manager Mocking

Problem: This doesn't work reliably:

# ❌ Brittle and complex
mock_session.get.return_value.__aenter__ = AsyncMock(return_value=mock_response)
mock_session.get.return_value.__aexit__ = AsyncMock(return_value=None)

Solution: Use specialized libraries or patch at higher levels:

# ✅ Clean with aioresponses
with aioresponses() as m:
    m.get("url", payload=data)
    # Test the actual HTTP call

4. Service Layer Mocking Strategy

Mock at the Client Level:

@pytest.fixture
def player_service_instance(self, mock_client):
    service = PlayerService()
    service._client = mock_client  # Inject mock client
    return service

This allows testing service logic while controlling API responses.

5. Global Instance Testing

Pattern for Singleton Services:

def test_global_service_independence():
    service1 = PlayerService()
    service2 = PlayerService()
    
    # Should be different instances
    assert service1 is not service2
    # But same configuration
    assert service1.endpoint == service2.endpoint

Testing Anti-Patterns to Avoid

1. Incomplete Test Data

# This will fail Pydantic validation
mock_data = {'id': 1, 'name': 'Test'}  # Missing required fields

2. Complex Manual Mocking

# Avoid complex AsyncMock setups for HTTP clients
mock_response = AsyncMock()
mock_response.__aenter__ = AsyncMock(...)  # Too complex

3. Testing Implementation Details

# Don't test internal method calls
assert mock_client.get.call_count == 2  # Brittle
# Instead test behavior
assert len(result) == 2  # What matters to users

4. Mixing Test Concerns

# Don't test multiple unrelated things in one test
def test_everything():  # Too broad
    # Test HTTP client
    # Test service logic  
    # Test model validation
    # All in one test - hard to debug

Best Practices Summary

Do:

  1. Use aioresponses for HTTP client testing
  2. Create complete model data with helper functions
  3. Test behavior, not implementation details
  4. Mock at appropriate levels (client level for services)
  5. Use realistic data that matches actual API responses
  6. Test error scenarios as thoroughly as happy paths
  7. Keep tests focused on single responsibilities

Don't:

  1. Manually mock async context managers - use specialized tools
  2. Use partial model data - always provide complete valid data
  3. Test implementation details - focus on behavior
  4. Mix multiple concerns in single tests
  5. Ignore error paths - test failure scenarios
  6. Skip integration scenarios - test realistic workflows

Running Tests

# Run all tests
pytest

# Run specific test files
pytest tests/test_services.py
pytest tests/test_api_client_with_aioresponses.py

# Run with coverage
pytest --cov=api --cov=services

# Run with verbose output
pytest -v

# Run specific test patterns
pytest -k "test_player" -v

Adding New Tests

For New API Endpoints:

  1. Add aioresponses-based tests in test_api_client_with_aioresponses.py
  2. Follow existing patterns for success/error scenarios

For New Services:

  1. Add service tests in test_services.py
  2. Create helper functions for complete model data
  3. Mock at the client level, not HTTP level

For New Models:

  1. Add model tests in test_models.py
  2. Test validation, serialization, and edge cases
  3. Use from_api_data() pattern for realistic data

Dependencies

Core testing dependencies in requirements.txt:

pytest>=7.0.0
pytest-asyncio>=0.21.0
pytest-mock>=3.10.0
aioresponses>=0.7.4        # Essential for HTTP testing

Troubleshooting Common Issues

"coroutine object does not support async context manager"

  • Cause: Manually mocking aiohttp async context managers
  • Solution: Use aioresponses instead of manual mocking

"ValidationError: Field required"

  • Cause: Incomplete test data for Pydantic models
  • Solution: Use helper functions that provide all required fields

"AssertionError: Regex pattern did not match"

  • Cause: Exception message doesn't match expected pattern
  • Solution: Check actual error message and adjust test expectations

Tests hanging or timing out

  • Cause: Unclosed aiohttp sessions or improper async handling
  • Solution: Ensure proper session cleanup and use async context managers

This guide should help maintain high-quality, reliable tests as the project grows!