Skip to content

Latest commit

 

History

History
252 lines (209 loc) · 8.05 KB

File metadata and controls

252 lines (209 loc) · 8.05 KB

Task 4: Implement Tests for utils/character_storage.py - COMPLETED ✅

Summary

Successfully implemented comprehensive test suite for utils/character_storage.py with 100% code coverage and 28 passing tests.

Test File Location

  • File: tests/utils/test_character_storage.py
  • Lines: 579 lines of test code
  • Coverage: 100% (49/49 statements covered)

Test Coverage Breakdown

1. TestSaveCharacter (6 tests)

Tests for save_character(name, char_data, selected_fields) function:

  • test_save_character_new_character - Creating new character with all fields
  • test_save_character_update_existing - Updating existing character, preserving unmodified fields
  • test_save_character_partial_fields - Saving only specific fields (e.g., dice only)
  • test_save_character_empty_fields_list - Handling empty fields list
  • test_save_character_database_error - Error handling for DB failures
  • test_save_character_missing_fields_in_data - Graceful handling of missing fields in input

Verifies:

  • Correct JSON structure in database
  • SQL INSERT/UPDATE queries
  • Field selection logic
  • Error logging with ❌ emoji
  • Return value (True/False)

2. TestGetCharacter (5 tests)

Tests for get_character(name) function:

  • test_get_character_exists - Retrieving existing character
  • test_get_character_not_found - Handling non-existent character (returns None)
  • test_get_character_invalid_json - Handling corrupted JSON data
  • test_get_character_database_error - Error handling for DB failures
  • test_get_character_empty_string_name - Handling empty name parameter

Verifies:

  • Correct SQL SELECT query
  • JSON parsing and deserialization
  • Error handling and logging
  • Return value (dict or None)

3. TestDeleteCharacter (4 tests)

Tests for delete_character(name) function:

  • test_delete_character_success - Successful deletion (DELETE 1)
  • test_delete_character_not_found - Handling non-existent character (DELETE 0)
  • test_delete_character_database_error - Error handling for DB failures
  • test_delete_character_empty_name - Handling empty name parameter

Verifies:

  • Correct SQL DELETE query
  • "DELETE 0" vs "DELETE 1" result handling
  • Error logging with ❌ emoji
  • Success logging with 🗑️ emoji
  • Return value (True/False)

4. TestGetAllNames (5 tests)

Tests for get_all_names() function:

  • test_get_all_names_multiple - Retrieving multiple character names
  • test_get_all_names_empty - Handling empty database
  • test_get_all_names_single - Retrieving single character
  • test_get_all_names_database_error - Error handling for DB failures
  • test_get_all_names_ordered - Verifying ORDER BY name clause

Verifies:

  • Correct SQL SELECT query with ORDER BY
  • Row extraction and name list building
  • Error handling (returns empty list on error)
  • Return value (list of strings)

5. TestCharacterStorageIntegration (3 tests)

Integration tests for complete workflows:

  • test_save_and_retrieve_workflow - Save then retrieve character
  • test_save_update_delete_workflow - Complete CRUD workflow
  • test_list_and_retrieve_multiple - List and retrieve multiple characters

Verifies:

  • End-to-end functionality
  • State consistency across operations
  • Multiple function interactions

6. TestEdgeCases (5 tests)

Edge cases and boundary conditions:

  • test_character_name_with_special_characters - Names with quotes, parentheses
  • test_character_with_unicode_name - Japanese/Unicode character names
  • test_character_with_very_long_name - 1000+ character names
  • test_character_with_large_data - Large data structures (100+ dice)
  • test_get_character_with_null_values - Handling null/None values in data

Verifies:

  • Robustness with unusual inputs
  • Unicode and special character handling
  • Large data handling
  • Null value preservation

Mocking Strategy

Database Mocking

@pytest.fixture
def mock_database():
    """Mock Database class"""
    with patch('utils.character_storage.Database') as mock_db:
        yield mock_db

Mocked Methods:

  • Database.execute() - AsyncMock for INSERT/UPDATE/DELETE
  • Database.fetchval() - AsyncMock for SELECT single value
  • Database.fetch() - AsyncMock for SELECT multiple rows

Return Value Examples:

  • execute(): "INSERT 1", "UPDATE 1", "DELETE 0", "DELETE 1"
  • fetchval(): JSON string or None
  • fetch(): List of dict rows

Logging Mocking

@pytest.fixture
def mock_log_message():
    """Mock log_message function"""
    with patch('utils.character_storage.log_message') as mock_log:
        yield mock_log

Verified:

  • Called with correct emoji (💾, ❌, 🗑️)
  • Called with appropriate messages
  • Not called when not expected

Test Fixtures

Sample Data Fixtures

@pytest.fixture
def sample_char_data():
    """Sample character data from initiative entry"""
    return {
        "hp": 100,
        "elements": ["fire", "water"],
        "atk": 15,
        "def_": 10,
        "favorite_dice": {"initiative": "1d20+5", "attack": "2d6+3"},
        "last_formula": "1d20+5"
    }

@pytest.fixture
def sample_stored_data():
    """Sample data as stored in database"""
    return {
        "stats": {"hp": 100, "elements": ["fire", "water"], "atk": 15, "def_": 10},
        "favorite_dice": {"initiative": "1d20+5", "attack": "2d6+3"},
        "initiative_formula": "1d20+5"
    }

Coverage Report

Name                             Stmts   Miss  Cover
-----------------------------------------------------
utils/character_storage.py          49      0   100%
tests/utils/test_character_storage.py  264      0   100%

All 49 statements in character_storage.py are covered:

  • Line 22-26: get_character() call and default initialization
  • Line 28-43: Field selection and update logic
  • Line 46-56: INSERT/UPDATE query execution and error handling
  • Line 60-68: get_character() function
  • Line 72-78: get_all_names() function
  • Line 82-92: delete_character() function

Test Execution Results

============================= 28 passed in 0.92s ==============================

All tests pass with:

  • ✅ 28/28 tests passing
  • ✅ 100% code coverage
  • ✅ No warnings or errors
  • ✅ Execution time: ~0.9 seconds

Key Testing Patterns

1. Async Test Support

@pytest.mark.asyncio
async def test_save_character_new_character(self, mock_database, ...):
    result = await save_character("Aragorn", sample_char_data, ["stats", "dice", "formula"])

2. Mock Assertion Patterns

# Verify function was called
mock_database.execute.assert_called_once()

# Verify call arguments
call_args = mock_database.execute.call_args
assert "INSERT INTO characters" in call_args[0][0]
assert call_args[0][1] == "Aragorn"

# Verify JSON data structure
saved_data = json.loads(call_args[0][2])
assert saved_data["stats"]["hp"] == 100

3. Error Handling Patterns

# Test exception handling
mock_database.execute = AsyncMock(side_effect=Exception("DB connection failed"))
result = await save_character("Aragorn", sample_char_data, ["stats"])
assert result is False
mock_log_message.assert_called()
assert "❌" in mock_log_message.call_args[0][0]

Dependencies

Test Dependencies:

  • pytest - Test framework
  • pytest-asyncio - Async test support
  • pytest-cov - Coverage reporting
  • unittest.mock - Mocking utilities

Module Dependencies:

  • utils.character_storage - Module under test
  • utils.db.Database - Mocked
  • utils.music.log_message - Mocked

Verification Checklist

  • ✅ Test file created: tests/utils/test_character_storage.py
  • ✅ All 4 functions tested:
    • save_character() - 6 tests
    • get_character() - 5 tests
    • delete_character() - 4 tests
    • get_all_names() - 5 tests
  • ✅ Database mocking implemented
  • ✅ Log message mocking implemented
  • ✅ Error handling tested
  • ✅ Edge cases covered
  • ✅ Integration workflows tested
  • ✅ 100% code coverage achieved
  • ✅ All 28 tests passing
  • ✅ No linting errors

Next Steps

Tas