# BaoLife/Lichun - Comprehensive Testing Plan

**Version:** 1.0
**Date:** 2025-11-14
**Status:** Planning Phase

---

## Executive Summary

This document outlines a comprehensive testing strategy for the BaoLife (Lichun) life simulation game backend. The goal is to achieve **80%+ code coverage** with a focus on critical game logic, data integrity, and system reliability.

**Current State:**
- **Existing Tests:** 29 test files covering basic functionality
- **Test Infrastructure:** pytest + pytest-asyncio + pytest-cov (ready to use)
- **Estimated Coverage:** ~30-40% (needs expansion)
- **Total Python Files:** 204 files, ~34,278 lines of core code

**Target State:**
- **Test Files:** 80+ comprehensive test files
- **Code Coverage:** 80%+ overall, 95%+ for critical paths
- **Test Types:** Unit, Integration, Property-based, Load, Regression
- **CI/CD:** Automated testing on all commits/PRs

---

## Table of Contents

1. [Testing Strategy Overview](#1-testing-strategy-overview)
2. [Test Priorities](#2-test-priorities)
3. [Core Systems Testing](#3-core-systems-testing)
4. [Event System Testing](#4-event-system-testing)
5. [Database & Persistence Testing](#5-database--persistence-testing)
6. [WebSocket & Networking Testing](#6-websocket--networking-testing)
7. [Game Mechanics Testing](#7-game-mechanics-testing)
8. [Integration & End-to-End Testing](#8-integration--end-to-end-testing)
9. [Performance & Load Testing](#9-performance--load-testing)
10. [Test Infrastructure & Tooling](#10-test-infrastructure--tooling)
11. [Implementation Roadmap](#11-implementation-roadmap)
12. [Success Metrics](#12-success-metrics)

---

## 1. Testing Strategy Overview

### 1.1 Testing Pyramid

```
        ╱╲
       ╱E2E╲         10% - End-to-End Tests (Full game simulations)
      ╱─────╲
     ╱ Integ.╲       30% - Integration Tests (Multi-module)
    ╱─────────╲
   ╱   Unit    ╲     60% - Unit Tests (Individual functions/classes)
  ╱─────────────╲
```

### 1.2 Test Categories

| Category | Purpose | Tools | Coverage Goal |
|----------|---------|-------|---------------|
| **Unit Tests** | Test individual functions/methods in isolation | pytest, pytest-mock | 70% |
| **Integration Tests** | Test interaction between modules | pytest, pytest-asyncio | 60% |
| **Property-Based Tests** | Test invariants with random inputs | hypothesis | Critical formulas |
| **Regression Tests** | Prevent breaking changes | pytest + fixtures | All bug fixes |
| **Load Tests** | Validate performance under stress | locust, pytest-benchmark | Key endpoints |
| **Contract Tests** | Validate API/WebSocket contracts | pytest + JSON schemas | 100% of messages |

### 1.3 Testing Principles

1. **Isolation:** Each test should be independent and idempotent
2. **Speed:** Unit tests < 100ms, Integration tests < 1s
3. **Clarity:** Test names should describe behavior (Given/When/Then)
4. **Coverage:** Focus on critical paths first, then expand
5. **Maintenance:** Tests should be as clean as production code
6. **Mocking:** Mock external dependencies (DB, API, WebSocket)
7. **Fixtures:** Reuse test data through shared fixtures

---

## 2. Test Priorities

### 2.1 Priority Classification

**P0 - Critical (Must Have - Week 1-2):**
- Game loop core logic
- Save/load game functionality
- Time progression accuracy
- Character state management
- Event triggering system
- Database transactions

**P1 - High (Should Have - Week 3-4):**
- Event system (all event types)
- Stats calculations (energy, money, age)
- Relationship management
- Education progression
- Job/career system
- WebSocket message handling

**P2 - Medium (Nice to Have - Week 5-6):**
- Health & weight calculations
- Monetization & shop
- Retention systems (quests, achievements)
- Dating & compatibility
- Tutorial flow

**P3 - Low (Future - Week 7+):**
- Avatar generation
- Analytics & statistics
- AI conversation edge cases
- Performance optimizations

### 2.2 Risk Assessment

| System | Failure Impact | Complexity | Test Priority |
|--------|----------------|------------|---------------|
| Game Loop | **Critical** - Game breaks | High | P0 |
| Save/Load | **Critical** - Data loss | High | P0 |
| Events | **High** - Bad UX | Medium | P1 |
| Stats | **High** - Game balance issues | Medium | P1 |
| WebSocket | **High** - Connection issues | High | P0 |
| Education | **Medium** - Feature broken | Low | P1 |
| Jobs | **Medium** - Feature broken | Low | P1 |
| Health | **Medium** - Balance issues | Medium | P2 |
| Shop | **Medium** - Revenue loss | Low | P2 |
| Dating | **Low** - Feature degraded | Medium | P2 |
| Avatar | **Low** - Cosmetic only | Low | P3 |

---

## 3. Core Systems Testing

### 3.1 Game Engine (`game_engine.py`)

**File:** `tests/unit/test_game_engine.py`

#### Test Cases:

**Time Progression:**
```python
def test_time_progression_single_minute():
    """Test that one tick advances time by one minute"""

def test_hour_rollover():
    """Test minute 59 → 0 and hour increments"""

def test_day_rollover():
    """Test hour 23 → 0 and date increments"""

def test_week_rollover():
    """Test dayOfWeek cycles through 0-6"""

def test_month_transitions():
    """Test month boundaries (28/29/30/31 days)"""

def test_leap_year_handling():
    """Test Feb 29 on leap years"""

def test_year_rollover():
    """Test Dec 31 → Jan 1 year increment"""
```

**Game State Updates:**
```python
def test_energy_depletion_per_tick():
    """Energy should decrease based on activity"""

def test_hunger_increase_over_time():
    """Hunger increases hourly"""

def test_money_updates_from_job():
    """Salary should be added on payday"""

def test_stat_boundaries():
    """Energy/hunger/etc should stay within 0-100"""

def test_birthday_triggers_age_increment():
    """Age should increment on birthday"""
```

**Event Checking:**
```python
def test_event_triggered_on_conditions_met():
    """Events should trigger when conditions match"""

def test_event_not_triggered_if_already_in_events_set():
    """No duplicate events in player.events"""

def test_day_event_triggers_on_specific_date():
    """Holiday events on correct dates"""

def test_tutorial_event_sequence():
    """Tutorial events in correct order"""
```

**Mock Strategy:**
- Mock `IGameStorage` to avoid DB calls
- Mock `IGameOutput` to capture messages
- Mock time.time() for deterministic testing

**Estimated Tests:** 30-40 test cases

---

### 3.2 Player & Person Classes (`core/models.py`)

**File:** `tests/unit/test_models.py`

#### Test Cases:

**playerClass:**
```python
def test_player_initialization():
    """Default values set correctly"""

def test_events_is_set_not_list():
    """player.events should be a set for O(1) lookups"""

def test_askedQuestions_is_set():
    """player.askedQuestions should be a set"""

def test_controller_state_transitions():
    """active ↔ inactive transitions valid"""

def test_status_transitions():
    """creating → active, cannot reverse"""

def test_set_serialization():
    """Sets should serialize/deserialize correctly"""
```

**personClass:**
```python
def test_person_creation_with_required_fields():
    """firstname, lastname, sex required"""

def test_age_calculation_from_ageHours():
    """ageYears = ageHours // (24 * 365)"""

def test_pronoun_setting_male():
    """Male → he/him/his"""

def test_pronoun_setting_female():
    """Female → she/her/hers"""

def test_pronoun_setting_nonbinary():
    """Nonbinary → they/them/their"""

def test_stat_defaults():
    """Energy=100, hunger=0, etc."""

def test_stat_boundaries_enforced():
    """Energy cannot be negative or > 100"""

def test_avatar_settings_initialization():
    """avatar_settings is SimpleNamespace"""

def test_get_mouth_type_based_on_happiness():
    """happiness < 30 → sad, 30-60 → neutral, > 60 → smile"""

def test_relationships_list_initialization():
    """Empty list by default"""

def test_dailyPlan_list_initialization():
    """Empty list by default"""
```

**locationClass, ActivityRecord, etc.:**
```python
def test_location_creation():
    """name, type, address fields"""

def test_education_record_tracks_progress():
    """GPA, focus, graduation date"""

def test_daily_event_scheduling():
    """Events trigger at specified hour"""

def test_one_time_event_with_completion_function():
    """Function executes on trigger"""

def test_scheduler_condition_evaluation():
    """Schedules only run when conditions met"""

def test_relationship_class_affinity_tracking():
    """Affinity updates correctly"""
```

**Estimated Tests:** 40-50 test cases

---

### 3.3 Character Manager (`character/character_manager.py`)

**File:** `tests/unit/test_character_manager.py`

#### Test Cases:

**Character Creation:**
```python
def test_create_character_with_valid_data():
    """Create with name, age, sex"""

def test_create_character_sets_birthday():
    """Birthday calculated from age"""

def test_create_character_initializes_stats():
    """Energy, hunger, etc. set to defaults"""

def test_create_character_sets_avatar():
    """Avatar generation called"""

def test_character_setup_adds_to_player():
    """player.c is set correctly"""
```

**Family & Relationships:**
```python
def test_add_parents_creates_two_parents():
    """Mother and father added"""

def test_add_child_updates_parent_relationship():
    """Parent's relationships updated"""

def test_add_siblings_age_appropriate():
    """Sibling ages make sense"""

def test_add_grandparents_only_if_parent_age_allows():
    """Grandparents exist if parents are old enough"""

def test_add_friend_creates_bidirectional_relationship():
    """Both characters have relationship"""

def test_relationship_affinity_initialization():
    """Family starts high, strangers low"""
```

**NPC Generation:**
```python
def test_create_classmates_age_appropriate():
    """Classmates within 1-2 years of age"""

def test_create_coworkers_at_same_location():
    """Coworkers share workplace"""

def test_get_random_classmate_returns_classmate():
    """Only returns actual classmates"""

def test_get_random_friend_returns_friend():
    """Only returns friends (affinity > threshold)"""
```

**Appearance:**
```python
def test_set_avatar_assigns_all_features():
    """Hair, eyes, skin, accessories set"""

def test_avatar_features_age_appropriate():
    """Children don't have facial hair"""

def test_get_lastname_returns_string():
    """Last name generated"""

def test_get_firstname_matches_sex():
    """Male/female name pools"""
```

**Estimated Tests:** 35-45 test cases

---

### 3.4 Stats Manager (`stats/stats_manager.py`)

**File:** `tests/unit/test_stats_manager.py`

#### Test Cases:

**Age Updates:**
```python
def test_update_age_increments_ageHours():
    """ageHours += hours_elapsed"""

def test_update_age_calculates_ageDays():
    """ageDays = ageHours // 24"""

def test_update_age_calculates_ageYears():
    """ageYears = ageDays // 365"""

def test_birthday_event_triggered_on_year_change():
    """Birthday event added when year increments"""

def test_age_transition_events():
    """Events at age 5, 10, 13, 16, 18, 21, etc."""
```

**Energy Calculations:**
```python
def test_get_peak_energy_child():
    """Ages 0-12: peak energy formula"""

def test_get_peak_energy_teen():
    """Ages 13-18: peak energy formula"""

def test_get_peak_energy_adult():
    """Ages 19-65: peak energy decreases slowly"""

def test_get_peak_energy_elderly():
    """Ages 65+: lower peak energy"""

def test_energy_depletion_during_activity():
    """Energy decreases based on activity type"""

def test_energy_restoration_during_sleep():
    """Energy increases during sleep schedule"""
```

**Mood & Happiness:**
```python
def test_handle_moods_updates_happiness():
    """Happiness affected by events, stats"""

def test_low_hunger_reduces_happiness():
    """Hunger > 80 → happiness decreases"""

def test_low_energy_reduces_happiness():
    """Energy < 20 → happiness decreases"""

def test_positive_events_increase_happiness():
    """Good events boost mood"""

def test_negative_events_decrease_happiness():
    """Bad events lower mood"""

def test_stress_calculation():
    """Stress from work, school, relationships"""
```

**Finances:**
```python
def test_handle_finances_adds_salary():
    """Job salary added on payday"""

def test_handle_finances_deducts_expenses():
    """Rent, bills deducted"""

def test_negative_money_handled():
    """Debt/overdraft logic"""
```

**Event Checking:**
```python
def test_check_events_age_filtering():
    """Only events for current age range"""

def test_check_events_deduplication():
    """Events already in player.events skipped"""

def test_check_day_events_on_correct_date():
    """Day events trigger on dayOfYear match"""

def test_check_tutorial_events_sequence():
    """Tutorial events in order"""

def test_check_dilemmas_conditions():
    """Dilemmas trigger when conditions met"""
```

**One-Time Events:**
```python
def test_parse_one_time_events_triggers_at_hour():
    """Event executes when hourOfDay matches"""

def test_parse_one_time_events_removes_after_execution():
    """Event removed from oneTimeEvents list"""

def test_parse_one_time_events_executes_function():
    """Completion function called"""
```

**Estimated Tests:** 40-50 test cases

---

### 3.5 Utilities (`utils/helpers.py`, `utils/game_speed.py`)

**File:** `tests/unit/test_utils.py`

#### Test Cases:

**Array Helpers:**
```python
def test_get_from_array_returns_item():
    """Returns item at index"""

def test_get_from_array_handles_out_of_bounds():
    """Returns None or default for invalid index"""

def test_rand_array_returns_random_item():
    """Returns item from array"""

def test_find_by_id_returns_matching_item():
    """Finds object with matching id"""

def test_find_by_id_returns_none_if_not_found():
    """None if no match"""

def test_find_where_filters_list():
    """Returns items matching predicate"""

def test_find_characters_by_type():
    """Filters characters by relationship type"""
```

**Date Helpers:**
```python
def test_ordinal_suffix_1st_2nd_3rd():
    """1→1st, 2→2nd, 3→3rd"""

def test_ordinal_suffix_11th_12th_13th():
    """11→11th, 12→12th, 13→13th (not 11st)"""

def test_get_week_day_0_to_6():
    """Returns correct day name"""

def test_upcoming_saturday_calculation():
    """Returns next Saturday date"""

def test_get_season_returns_correct_season():
    """Spring, Summer, Fall, Winter based on month"""

def test_generate_random_date_in_range():
    """Random date between start and end"""
```

**Game Speed:**
```python
def test_validate_game_speed_enforces_min():
    """Speed < SPEED_MIN → SPEED_MIN"""

def test_validate_game_speed_enforces_max():
    """Speed > SPEED_MAX → SPEED_MAX"""

def test_validate_game_speed_allows_paused():
    """SPEED_PAUSED (10000) allowed"""

def test_get_speed_button_values_returns_presets():
    """Returns valid speed presets"""
```

**Estimated Tests:** 25-30 test cases

---

## 4. Event System Testing

### 4.1 Event Registry (`event_registry.py`)

**File:** `tests/unit/test_event_registry.py`

#### Test Cases:

**Event Registration:**
```python
def test_register_event_adds_to_registry():
    """Event appears in registry"""

def test_register_event_with_age_range():
    """Event indexed by age range"""

def test_register_event_with_conditions():
    """Event indexed by conditions"""

def test_register_duplicate_event_raises_error():
    """Cannot register same event_id twice"""

def test_register_event_without_conditions():
    """Event added to _no_conditions list"""
```

**Event Filtering:**
```python
def test_get_applicable_events_filters_by_age():
    """Only returns events for player's age"""

def test_get_applicable_events_requires_relationship():
    """Only returns events if relationship exists"""

def test_get_applicable_events_requires_job():
    """Only returns events if player has job"""

def test_get_applicable_events_checks_day_of_year():
    """Only returns events for current day"""

def test_get_applicable_events_combines_conditions():
    """AND logic for multiple conditions"""

def test_get_applicable_events_excludes_completed():
    """Events in player.events excluded"""
```

**Performance:**
```python
def test_get_applicable_events_performance_1000_events():
    """O(1) filtering with large registry"""
```

**Estimated Tests:** 15-20 test cases

---

### 4.2 Event Handlers (`event_handlers.py`)

**File:** `tests/unit/test_event_handlers.py`

#### Test Cases:

**Handler Registration:**
```python
def test_register_handler_adds_to_registry():
    """Handler registered successfully"""

def test_register_handler_prevents_dunder_methods():
    """__init__, __dict__ rejected"""

def test_register_handler_prevents_private_methods():
    """_private methods rejected"""

def test_register_handler_allows_valid_names():
    """Normal function names accepted"""
```

**Handler Execution:**
```python
def test_execute_handler_calls_function():
    """Registered function executed"""

def test_execute_handler_passes_arguments():
    """Arguments forwarded correctly"""

def test_execute_handler_returns_result():
    """Return value propagated"""

def test_execute_handler_raises_on_unknown():
    """Unknown handler raises error"""

def test_execute_handler_raises_on_invalid_signature():
    """Invalid function signature rejected"""
```

**Security:**
```python
def test_handler_cannot_access_globals():
    """No access to __globals__"""

def test_handler_cannot_import_modules():
    """Cannot import dangerous modules"""

def test_handler_sandboxing():
    """Execution sandboxed properly"""
```

**Estimated Tests:** 15-20 test cases

---

### 4.3 Event Base Classes (`events/base.py`)

**File:** `tests/unit/test_event_base.py`

#### Test Cases:

**messageEvent:**
```python
def test_message_event_creation():
    """Creates with title, description, datetime"""

def test_message_event_with_cost():
    """Cost deducted from money"""

def test_message_event_with_reward():
    """Reward added to money"""

def test_message_event_with_stat_changes():
    """energyCost, happinessReward applied"""

def test_message_event_serialization():
    """Converts to dict for WebSocket"""

def test_message_event_does_not_pause_game():
    """gameSpeed unchanged"""
```

**questionEvent:**
```python
def test_question_event_creation():
    """Creates with title, question, answers"""

def test_question_event_pauses_game():
    """gameSpeed set to SPEED_QUESTION_PAUSE"""

def test_question_event_answer_validation():
    """Only valid answer IDs accepted"""

def test_question_event_executes_answer_function():
    """Answer's function called on selection"""

def test_question_event_applies_answer_costs():
    """Answer cost/reward applied"""

def test_question_event_removes_from_queue_after_answer():
    """Event removed from player.askedQuestions"""

def test_question_event_resumes_game_after_answer():
    """gameSpeed restored"""
```

**answerOption:**
```python
def test_answer_option_creation():
    """text, function, cost, reward"""

def test_answer_option_with_stat_effects():
    """Stat changes defined"""

def test_answer_option_function_execution():
    """Function called when selected"""
```

**dilemmaClass:**
```python
def test_dilemma_creation():
    """Multi-step decision tree"""

def test_dilemma_state_progression():
    """Moves through steps correctly"""

def test_dilemma_completion():
    """Completes when all steps done"""

def test_dilemma_serialization():
    """Complex state serializes correctly"""
```

**Helper Functions:**
```python
def test_message_function_creates_message_event():
    """messageFunction() returns messageEvent"""

def test_question_function_creates_question_event():
    """questionFunction() returns questionEvent"""

def test_message_function_adds_to_player_events():
    """Event added to player.events set"""

def test_question_function_adds_to_asked_questions():
    """Event added to player.askedQuestions set"""
```

**Estimated Tests:** 30-35 test cases

---

### 4.4 Event Categories

Each event category needs targeted tests. Create one test file per category.

**Files:**
- `tests/unit/events/test_childhood_events.py`
- `tests/unit/events/test_adolescence_events.py`
- `tests/unit/events/test_education_events.py`
- `tests/unit/events/test_adulthood_events.py`
- `tests/unit/events/test_health_events.py`
- `tests/unit/events/test_holiday_events.py`
- `tests/unit/events/test_random_events.py`
- `tests/unit/events/test_dilemmas.py`

**Test Pattern for Each Category:**
```python
def test_event_triggers_at_correct_age():
    """Event only triggers in age range"""

def test_event_requires_conditions():
    """Event needs job/relationship/education"""

def test_event_not_duplicate():
    """Event fname not in player.events"""

def test_event_applies_costs_correctly():
    """Money/energy/stats updated"""

def test_event_choice_consequences():
    """Different answers → different outcomes"""

def test_event_chain_progression():
    """Multi-part events sequence correctly"""
```

**Estimated Tests per Category:** 10-15 test cases
**Total Event Tests:** 80-120 test cases

---

## 5. Database & Persistence Testing

### 5.1 Database Connection Pool (`database_async.py`)

**File:** `tests/unit/test_database_async.py`

#### Test Cases:

**Pool Management:**
```python
def test_initialize_pool_creates_pool():
    """Pool created with correct size"""

def test_initialize_pool_connects_to_database():
    """Connects to correct DB"""

def test_close_pool_closes_all_connections():
    """All connections closed gracefully"""

def test_pool_size_respected():
    """Max connections not exceeded"""

def test_pool_connection_reuse():
    """Connections reused after release"""

def test_pool_exhaustion_waits():
    """Waits for available connection if pool full"""
```

**Query Execution:**
```python
def test_execute_query_insert():
    """INSERT query executes"""

def test_execute_query_update():
    """UPDATE query executes"""

def test_execute_query_delete():
    """DELETE query executes"""

def test_execute_query_with_parameters():
    """Parameterized queries work"""

def test_execute_query_sql_injection_prevented():
    """Parameters prevent injection"""
```

**Fetch Operations:**
```python
def test_fetch_one_returns_tuple():
    """Returns single row as tuple"""

def test_fetch_all_returns_list():
    """Returns all rows as list"""

def test_fetch_dict_one_returns_dict():
    """Returns single row as dict"""

def test_fetch_dict_all_returns_list_of_dicts():
    """Returns all rows as list of dicts"""

def test_fetch_empty_result():
    """Empty result handled correctly"""
```

**Transactions:**
```python
def test_transaction_commits():
    """Transaction commits on success"""

def test_transaction_rolls_back_on_error():
    """Transaction rolls back on exception"""

def test_transaction_context_manager():
    """Context manager works correctly"""

def test_nested_transactions():
    """Savepoints for nested transactions"""

def test_transaction_isolation():
    """Isolation levels respected"""
```

**Error Handling:**
```python
def test_connection_lost_reconnects():
    """Auto-reconnect on connection loss"""

def test_query_timeout_handled():
    """Timeout doesn't crash pool"""

def test_database_down_raises_error():
    """Clear error when DB unavailable"""
```

**Estimated Tests:** 30-35 test cases

---

### 5.2 Game Persistence (`database/db_operations.py`)

**File:** `tests/integration/test_game_persistence.py`

#### Test Cases:

**Save Operations:**
```python
def test_save_game_creates_record():
    """saveGame() inserts into DB"""

def test_save_game_async_creates_record():
    """saveGameAsync() inserts into DB"""

def test_save_game_updates_existing():
    """UPDATE existing game save"""

def test_save_game_serializes_player_correctly():
    """Player object pickled correctly"""

def test_save_game_handles_large_player_object():
    """Large saves (many NPCs) handled"""

def test_save_game_sets_timestamp():
    """Timestamp updated on save"""
```

**Load Operations:**
```python
def test_load_game_returns_player():
    """loadGame() returns playerClass"""

def test_load_game_async_returns_player():
    """loadGameAsync() returns playerClass"""

def test_load_game_deserializes_correctly():
    """Unpickle restores all attributes"""

def test_load_game_not_found_returns_none():
    """Returns None if game doesn't exist"""

def test_load_game_corrupted_data_handled():
    """Corrupted pickle handled gracefully"""
```

**Round-Trip Tests:**
```python
def test_save_load_roundtrip_preserves_data():
    """Save → Load returns identical player"""

def test_save_load_preserves_sets():
    """player.events set preserved"""

def test_save_load_preserves_relationships():
    """Relationship list preserved"""

def test_save_load_preserves_locations():
    """Location list preserved"""

def test_save_load_preserves_nested_objects():
    """personClass objects within player preserved"""
```

**Pickle Compatibility:**
```python
def test_refactoring_unpickler_maps_old_classes():
    """Old class paths mapped to new paths"""

def test_load_old_save_file():
    """Load save from pre-refactor version"""

def test_load_save_missing_attributes():
    """Missing attributes get defaults"""

def test_pickle_version_migration():
    """Automatic migration from old formats"""
```

**Conversation Persistence:**
```python
def test_save_conversation_message():
    """saveConversationMessage() works"""

def test_mark_conversation_as_read():
    """markConversationAsRead() updates status"""

def test_load_conversation_history():
    """Conversation history loaded correctly"""
```

**Estimated Tests:** 30-35 test cases

---

### 5.3 Database Migrations

**File:** `tests/integration/test_migrations.py`

#### Test Cases:

```python
def test_all_migrations_apply_cleanly():
    """All migration files apply without errors"""

def test_migrations_are_idempotent():
    """Running migrations twice doesn't break"""

def test_migration_rollback():
    """Rollback reverses migration"""

def test_schema_matches_models():
    """Database schema matches Python models"""
```

**Estimated Tests:** 5-10 test cases

---

## 6. WebSocket & Networking Testing

### 6.1 WebSocket Handler (`server/websocket_handlers.py`)

**File:** `tests/integration/test_websocket_handlers.py`

#### Test Cases:

**Connection Lifecycle:**
```python
def test_websocket_connection_accepted():
    """Client can connect"""

def test_websocket_connection_rejected_if_max_reached():
    """Max connections enforced"""

def test_websocket_disconnection_cleanup():
    """Connection removed from registry on disconnect"""

def test_websocket_reconnection_loads_game():
    """Reconnection resumes game"""

def test_websocket_multiple_connections_same_user():
    """Handle multiple tabs/devices"""
```

**Message Handling:**
```python
def test_websocket_receives_init_message():
    """Init message processed"""

def test_websocket_receives_command_message():
    """Command message processed"""

def test_websocket_receives_speed_message():
    """Speed change processed"""

def test_websocket_receives_question_response():
    """Question response processed"""

def test_websocket_receives_conversation_message():
    """Conversation message processed"""

def test_websocket_receives_invalid_message_type():
    """Invalid message type handled gracefully"""

def test_websocket_receives_malformed_json():
    """Malformed JSON handled gracefully"""
```

**Rate Limiting:**
```python
def test_websocket_rate_limiting_enforced():
    """Too many messages → throttled"""

def test_websocket_rate_limiting_resets():
    """Rate limit resets after time window"""

def test_websocket_rate_limiting_per_user():
    """Rate limiting per connection"""
```

**Error Handling:**
```python
def test_websocket_error_doesnt_crash_server():
    """Error in one connection doesn't affect others"""

def test_websocket_connection_timeout():
    """Idle connections closed after timeout"""

def test_websocket_ping_pong():
    """Ping/pong keepalive works"""
```

**Estimated Tests:** 20-25 test cases

---

### 6.2 Message Serialization (`server/websocket_messaging.py`)

**File:** `tests/unit/test_websocket_messaging.py`

#### Test Cases:

**Message Batching:**
```python
def test_batched_update_collects_messages():
    """Messages added to batch"""

def test_batched_update_sends_after_threshold():
    """Batch sent when size threshold reached"""

def test_batched_update_sends_after_timeout():
    """Batch sent after time threshold"""

def test_batched_update_deduplicates_messages():
    """Duplicate messages removed"""

def test_batched_update_preserves_order():
    """Message order preserved"""
```

**Serialization:**
```python
def test_complex_handler_serializes_datetime():
    """datetime → ISO string"""

def test_complex_handler_serializes_set():
    """set → list"""

def test_complex_handler_serializes_namespace():
    """SimpleNamespace → dict"""

def test_complex_handler_serializes_nested_objects():
    """Nested objects handled"""

def test_complex_handler_handles_circular_references():
    """Circular refs don't cause infinite loop"""
```

**Message Types:**
```python
def test_send_player_object_message():
    """playerObject message format"""

def test_send_update_message():
    """u (update) message format"""

def test_send_message_event():
    """messageEvent message format"""

def test_send_question_event():
    """questionEvent message format"""

def test_send_conversation_event():
    """conversationEvent message format"""

def test_send_person_object():
    """personObject message format"""
```

**Estimated Tests:** 20-25 test cases

---

### 6.3 Command Dispatcher (`server/command_dispatcher.py`)

**File:** `tests/unit/test_command_dispatcher.py`

#### Test Cases:

**Command Routing:**
```python
def test_dispatch_init_command():
    """Init command routes correctly"""

def test_dispatch_start_command():
    """Start command routes correctly"""

def test_dispatch_stop_command():
    """Stop command routes correctly"""

def test_dispatch_restart_command():
    """Restart command routes correctly"""

def test_dispatch_speed_command():
    """Speed command routes correctly"""

def test_dispatch_question_response():
    """Question response routes correctly"""

def test_dispatch_conversation_message():
    """Conversation message routes correctly"""

def test_dispatch_character_setup():
    """Character setup routes correctly"""

def test_dispatch_apply_for_job():
    """Job application routes correctly"""

def test_dispatch_purchase_item():
    """Item purchase routes correctly"""

def test_dispatch_claim_event():
    """Event claim routes correctly"""

def test_dispatch_unknown_command():
    """Unknown command handled gracefully"""
```

**Command Validation:**
```python
def test_validate_init_requires_user_id():
    """Init requires userID field"""

def test_validate_speed_requires_numeric_value():
    """Speed requires number"""

def test_validate_question_response_requires_id_and_answer():
    """Question response requires both fields"""

def test_validate_conversation_requires_message():
    """Conversation requires message"""
```

**Estimated Tests:** 20-25 test cases

---

## 7. Game Mechanics Testing

### 7.1 Education System (`education/education_manager.py`)

**File:** `tests/unit/test_education_manager.py`

#### Test Cases:

**School Enrollment:**
```python
def test_set_education_elementary_school():
    """Enroll in elementary school"""

def test_set_education_high_school():
    """Enroll in high school"""

def test_set_education_college():
    """Enroll in college"""

def test_set_education_validates_age():
    """Age-appropriate enrollment"""

def test_set_education_creates_education_record():
    """EducationRecord created"""

def test_set_education_updates_current_education():
    """current_education pointer updated"""
```

**Education Progression:**
```python
def test_handle_education_increases_gpa():
    """GPA updated based on performance"""

def test_handle_education_graduation():
    """Graduation triggers at completion"""

def test_handle_education_failing():
    """Low GPA consequences"""

def test_handle_education_focus_effects():
    """Focus affects GPA in subject areas"""
```

**Focus Management:**
```python
def test_update_focus_changes_current_focus():
    """Focus changed successfully"""

def test_get_focus_returns_current_focus():
    """Current focus returned"""

def test_focus_affects_performance():
    """Higher focus → better grades"""
```

**Extracurriculars:**
```python
def test_set_extracurricular_adds_activity():
    """Activity added to list"""

def test_apply_for_extracurricular_requires_conditions():
    """Some activities have requirements"""

def test_quit_extracurricular_removes_activity():
    """Activity removed"""

def test_extracurricular_affects_stats():
    """Activities affect happiness, energy, etc."""
```

**GPA Calculation:**
```python
def test_gpa_calculation_formula():
    """GPA calculated correctly from grades"""

def test_gpa_weighted_by_focus():
    """Focus affects GPA"""

def test_gpa_affected_by_extracurriculars():
    """Activities can boost/lower GPA"""
```

**Estimated Tests:** 30-35 test cases

---

### 7.2 Job/Career System (`jobs/job_manager.py`)

**File:** `tests/unit/test_job_manager.py`

#### Test Cases:

**Job Assignment:**
```python
def test_set_job_assigns_occupation():
    """Job assigned to character"""

def test_set_job_validates_age():
    """Minimum age for employment"""

def test_set_job_validates_education():
    """Education requirements checked"""

def test_random_job_returns_valid_job():
    """Random job appropriate for character"""
```

**Job Progression:**
```python
def test_handle_job_adds_salary():
    """Salary added to money"""

def test_handle_job_promotion():
    """Promotion after X time/performance"""

def test_handle_job_demotion():
    """Demotion for poor performance"""

def test_handle_job_firing():
    """Fired for bad performance"""
```

**Job Application:**
```python
def test_apply_for_job_requires_qualifications():
    """Application rejected if unqualified"""

def test_apply_for_job_success():
    """Application accepted if qualified"""

def test_apply_for_job_creates_event():
    """Event generated for job offer"""
```

**Quit Job:**
```python
def test_quit_job_removes_occupation():
    """Job removed from character"""

def test_quit_job_updates_schedules():
    """Work schedule removed"""

def test_quit_job_triggers_event():
    """Exit event generated"""
```

**Salary Calculation:**
```python
def test_salary_based_on_job_level():
    """Higher level → higher salary"""

def test_salary_based_on_performance():
    """Performance affects salary"""

def test_salary_frequency_weekly():
    """Weekly jobs pay weekly"""

def test_salary_frequency_monthly():
    """Monthly jobs pay monthly"""
```

**Estimated Tests:** 25-30 test cases

---

### 7.3 Health System (`health/health_manager.py`)

**File:** `tests/unit/test_health_manager.py`

#### Test Cases:

**Weight Management:**
```python
def test_get_weight_type_underweight():
    """BMI < 18.5 → underweight"""

def test_get_weight_type_normal():
    """BMI 18.5-24.9 → normal"""

def test_get_weight_type_overweight():
    """BMI 25-29.9 → overweight"""

def test_get_weight_type_obese():
    """BMI >= 30 → obese"""

def test_handle_weight_updates_based_on_diet():
    """Eating habits affect weight"""

def test_handle_weight_updates_based_on_activity():
    """Exercise affects weight"""
```

**Habits:**
```python
def test_set_habits_adds_habit():
    """Habit added to list"""

def test_quit_habit_removes_habit():
    """Habit removed"""

def test_stop_quit_habit_fails_quitting():
    """Quitting failed, habit returns"""

def test_handle_habit_changes_affects_stats():
    """Smoking → lower health, etc."""

def test_habit_addiction_level():
    """Harder to quit high-addiction habits"""
```

**Health Conditions:**
```python
def test_get_health_conditions_returns_list():
    """List of active conditions"""

def test_handle_health_develops_conditions():
    """Age, habits cause conditions"""

def test_handle_health_treats_conditions():
    """Treatment removes conditions"""

def test_health_conditions_affect_stats():
    """Illness → lower energy, etc."""
```

**Death System:**
```python
def test_handle_death_calculates_probability():
    """Death chance based on age, health"""

def test_update_death_chance_increases_with_age():
    """Older → higher death chance"""

def test_handle_death_triggers_when_occurred():
    """Death event when chance succeeds"""

def test_handle_death_ends_game():
    """Game ends on death"""
```

**Hunger/Thirst:**
```python
def test_handle_hunger_increases_over_time():
    """Hunger increases hourly"""

def test_meal_event_reduces_hunger():
    """Eating reduces hunger"""

def test_meal_event_affects_weight():
    """Meals affect weight over time"""

def test_hunger_affects_energy():
    """High hunger → low energy"""
```

**Estimated Tests:** 30-35 test cases

---

### 7.4 Relationship System (`relationships/relationship_manager.py`)

**File:** `tests/unit/test_relationship_manager.py`

#### Test Cases:

**Affinity Updates:**
```python
def test_update_affinity_increases():
    """Positive interaction → higher affinity"""

def test_update_affinity_decreases():
    """Negative interaction → lower affinity"""

def test_update_affinity_boundaries():
    """Affinity stays within 0-100"""

def test_update_affinity_bidirectional():
    """Both parties' affinity updated"""
```

**Relationship Handling:**
```python
def test_handle_relationships_updates_all():
    """All relationships processed"""

def test_get_rel_data_returns_relationship():
    """Finds relationship by person ID"""

def test_get_rel_data_creates_if_not_exists():
    """Creates relationship if new"""
```

**Romance:**
```python
def test_romance_initiates_relationship():
    """Romance started"""

def test_get_active_relationship_returns_partner():
    """Active romantic relationship found"""

def test_break_up_ends_relationship():
    """Breakup ends romance"""

def test_break_up_affects_affinity():
    """Breakup lowers affinity"""
```

**Dating:**
```python
def test_partner_gift_increases_affinity():
    """Gifts boost relationship"""

def test_date_night_creates_event():
    """Date event generated"""

def test_get_date_ideas_returns_activities():
    """Date activities listed"""

def test_date_affects_affinity():
    """Good date → higher affinity"""
```

**Estimated Tests:** 20-25 test cases

---

### 7.5 Dating System (`dating/` modules)

**Files:**
- `tests/unit/test_dating_compatibility.py`
- `tests/unit/test_dating_bio_generator.py`
- `tests/unit/test_dating_matching.py`
- `tests/unit/test_dating_activities.py`

#### Test Cases:

**Compatibility:**
```python
def test_calculate_compatibility_score():
    """Compatibility calculated correctly"""

def test_compatibility_based_on_interests():
    """Shared interests → higher score"""

def test_compatibility_based_on_values():
    """Shared values → higher score"""

def test_compatibility_based_on_personality():
    """Personality match → higher score"""
```

**Bio Generation:**
```python
def test_generate_bio_creates_profile():
    """Bio generated from character data"""

def test_bio_includes_interests():
    """Interests included in bio"""

def test_bio_tone_matches_personality():
    """Bio reflects personality"""
```

**Matching:**
```python
def test_find_matches_returns_compatible():
    """Returns high-compatibility matches"""

def test_find_matches_filters_by_preferences():
    """Age, gender preferences respected"""

def test_find_matches_excludes_existing_relationships():
    """No matches with current/past partners"""
```

**Date Activities:**
```python
def test_get_date_activity_age_appropriate():
    """Activity suitable for age"""

def test_date_activity_affects_affinity():
    """Activity outcome affects relationship"""

def test_date_activity_costs_money():
    """Activities have costs"""
```

**Estimated Tests:** 25-30 test cases

---

### 7.6 Shop/Monetization (`shop/`, `monetization/`)

**Files:**
- `tests/unit/test_shop_manager.py`
- `tests/unit/test_monetization.py`

#### Test Cases:

**Store Items:**
```python
def test_get_store_items_returns_catalog():
    """Store catalog returned"""

def test_purchase_item_deducts_money():
    """Money deducted on purchase"""

def test_purchase_item_adds_to_inventory():
    """Item added to player inventory"""

def test_purchase_item_insufficient_funds():
    """Purchase fails if not enough money"""
```

**In-App Purchases:**
```python
def test_get_iap_items_returns_catalog():
    """IAP catalog returned"""

def test_purchase_iap_item_adds_diamonds():
    """Diamonds added on purchase"""

def test_purchase_iap_item_validates_receipt():
    """Receipt validation required"""
```

**Energy Refills:**
```python
def test_purchase_energy_refill_restores_energy():
    """Energy restored to max"""

def test_purchase_energy_refill_deducts_diamonds():
    """Diamonds deducted"""

def test_purchase_energy_refill_rate_limited():
    """Cannot spam energy refills"""
```

**Time Skips:**
```python
def test_purchase_time_skip_advances_time():
    """Time advanced by skip amount"""

def test_purchase_time_skip_deducts_diamonds():
    """Diamonds deducted"""

def test_purchase_time_skip_processes_events():
    """Events during skip processed"""
```

**Idempotency:**
```python
def test_purchase_idempotency():
    """Duplicate purchase requests prevented"""

def test_transaction_validation_prevents_duplicates():
    """Validation manager prevents dupes"""
```

**Estimated Tests:** 20-25 test cases

---

### 7.7 Retention Systems (`retention/`)

**Files:**
- `tests/unit/test_daily_quests.py`
- `tests/unit/test_daily_rewards.py`
- `tests/unit/test_achievements.py`
- `tests/unit/test_tutorial.py`

#### Test Cases:

**Daily Quests:**
```python
def test_get_daily_quests_returns_quests():
    """Daily quests returned"""

def test_complete_quest_awards_reward():
    """Quest completion gives reward"""

def test_daily_quests_reset_daily():
    """Quests reset at midnight"""

def test_quest_progress_tracked():
    """Progress saved between sessions"""
```

**Daily Rewards:**
```python
def test_claim_daily_reward_once_per_day():
    """Reward claimed once per day"""

def test_daily_reward_streak_tracked():
    """Login streak tracked"""

def test_daily_reward_streak_broken_if_miss_day():
    """Streak resets if day missed"""

def test_daily_reward_increases_with_streak():
    """Longer streak → better rewards"""
```

**Achievements:**
```python
def test_achievement_unlock_conditions():
    """Achievement unlocks when conditions met"""

def test_achievement_awards_reward():
    """Achievement gives reward"""

def test_achievement_progress_tracked():
    """Progress toward achievement saved"""

def test_achievement_not_re-awarded():
    """Achievement only awarded once"""
```

**Tutorial:**
```python
def test_tutorial_starts_for_new_player():
    """Tutorial begins for new accounts"""

def test_tutorial_progresses_through_steps():
    """Tutorial steps in sequence"""

def test_tutorial_completion_tracked():
    """Tutorial completion saved"""

def test_tutorial_can_be_skipped():
    """Tutorial skip option works"""
```

**Estimated Tests:** 25-30 test cases

---

## 8. Integration & End-to-End Testing

### 8.1 Full Game Loop Integration

**File:** `tests/integration/test_full_game_loop.py`

#### Test Cases:

```python
def test_new_game_creation_to_first_birthday():
    """Create character, simulate to first birthday"""

def test_childhood_to_elementary_school():
    """Birth → Age 5 → Elementary school enrollment"""

def test_elementary_to_high_school_transition():
    """Age 14 → High school transition"""

def test_high_school_graduation():
    """Complete high school → graduation event"""

def test_college_enrollment_and_graduation():
    """Enroll in college → graduate"""

def test_first_job_application_and_employment():
    """Apply for job → get hired → receive salary"""

def test_romantic_relationship_lifecycle():
    """Meet → date → relationship → breakup"""

def test_full_life_simulation_birth_to_death():
    """Simulate entire life (birth → death)"""
```

**Estimated Tests:** 10-15 test cases

---

### 8.2 Multi-Character Interactions

**File:** `tests/integration/test_multi_character.py`

#### Test Cases:

```python
def test_family_interactions():
    """Parents, siblings, children interact"""

def test_friend_affinity_changes():
    """Friendships develop/decay over time"""

def test_classmate_interactions():
    """School events with classmates"""

def test_coworker_interactions():
    """Work events with coworkers"""

def test_romantic_partner_daily_interactions():
    """Daily interactions with partner"""
```

**Estimated Tests:** 8-12 test cases

---

### 8.3 Event Chain Testing

**File:** `tests/integration/test_event_chains.py`

#### Test Cases:

```python
def test_education_event_chain():
    """Enrollment → Classes → Exams → Graduation"""

def test_career_event_chain():
    """Job application → Hire → Promotion → Retirement"""

def test_romance_event_chain():
    """Meet → Date → Relationship → Marriage → Children"""

def test_health_event_chain():
    """Develop habit → Health decline → Treatment → Recovery"""

def test_dilemma_multi_step_progression():
    """Dilemma part 1 → part 2 → resolution"""
```

**Estimated Tests:** 8-12 test cases

---

### 8.4 WebSocket End-to-End

**File:** `tests/e2e/test_websocket_e2e.py`

#### Test Cases:

```python
def test_client_connect_init_start_game():
    """Full WebSocket lifecycle"""

def test_client_receives_events():
    """Events sent to client correctly"""

def test_client_answers_question():
    """Question answered, game resumes"""

def test_client_changes_speed():
    """Speed change applied"""

def test_client_disconnects_and_reconnects():
    """Game state preserved on reconnect"""

def test_multiple_clients_same_user():
    """Multiple tabs/devices synced"""
```

**Estimated Tests:** 8-12 test cases

---

## 9. Performance & Load Testing

### 9.1 Load Testing

**File:** `tests/load/test_websocket_load.py`

#### Test Strategy:

Use **Locust** for load testing WebSocket connections.

**Scenarios:**
```python
def test_100_concurrent_connections():
    """100 players connected simultaneously"""

def test_1000_concurrent_connections():
    """1000 players (max expected)"""

def test_connection_spike():
    """Rapid connection increase (0→1000 in 10s)"""

def test_message_throughput():
    """Messages per second capacity"""

def test_database_pool_under_load():
    """DB pool doesn't exhaust"""

def test_memory_usage_under_load():
    """Memory doesn't leak"""
```

**Metrics to Track:**
- Connection acceptance rate
- Message latency (p50, p95, p99)
- Memory usage
- CPU usage
- Database connection pool usage
- Error rate

**Estimated Tests:** 8-10 scenarios

---

### 9.2 Performance Benchmarking

**File:** `tests/performance/test_benchmarks.py`

#### Test Cases:

Use **pytest-benchmark** for performance tests.

```python
def test_game_tick_performance(benchmark):
    """Game tick should complete < 50ms"""

def test_event_filtering_performance(benchmark):
    """Event filtering with 1000 events < 10ms"""

def test_save_game_performance(benchmark):
    """Save game < 200ms"""

def test_load_game_performance(benchmark):
    """Load game < 300ms"""

def test_character_creation_performance(benchmark):
    """Character creation < 100ms"""

def test_affinity_calculation_performance(benchmark):
    """Affinity update < 5ms"""
```

**Performance Targets:**
- Game tick: < 50ms
- Event filtering: < 10ms
- Save game: < 200ms
- Load game: < 300ms
- Character creation: < 100ms

**Estimated Tests:** 10-15 benchmarks

---

## 10. Test Infrastructure & Tooling

### 10.1 Test Configuration

**File:** `pytest.ini`

```ini
[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
asyncio_mode = auto

# Coverage settings
addopts =
    --cov=ws
    --cov-report=html
    --cov-report=term-missing
    --cov-report=xml
    --cov-fail-under=80
    --verbose
    --strict-markers
    --tb=short

# Test markers
markers =
    unit: Unit tests (fast, isolated)
    integration: Integration tests (slower, DB/WebSocket)
    e2e: End-to-end tests (slowest, full system)
    load: Load and performance tests
    slow: Slow tests (> 1s)
    db: Tests requiring database
    websocket: Tests requiring WebSocket
    property: Property-based tests

# Timeout settings
timeout = 300
timeout_method = thread

# Parallel execution
# Run with: pytest -n auto
```

### 10.2 Fixtures Organization

**File:** `tests/conftest.py`

```python
import pytest
from ws.core.models import playerClass, personClass
from ws.game_engine import GameEngine
from tests.mocks.storage_mock import MockStorage
from tests.mocks.output_mock import MockOutput
from tests.mocks.services_mock import MockConversationService

# Database fixtures
@pytest.fixture(scope="session")
def db_pool():
    """Async database connection pool for tests"""

@pytest.fixture(scope="function")
def db_transaction():
    """Database transaction (rollback after test)"""

# Player fixtures
@pytest.fixture
def newborn_player():
    """Player with newborn character"""

@pytest.fixture
def child_player():
    """Player with child (age 8)"""

@pytest.fixture
def teen_player():
    """Player with teenager (age 16)"""

@pytest.fixture
def adult_player():
    """Player with adult (age 30)"""

# Game engine fixtures
@pytest.fixture
def game_engine():
    """GameEngine with mock dependencies"""

@pytest.fixture
def mock_storage():
    """Mock storage for testing"""

@pytest.fixture
def mock_output():
    """Mock output for testing"""

# WebSocket fixtures
@pytest.fixture
def websocket_client():
    """WebSocket test client"""

@pytest.fixture
def websocket_server():
    """Running WebSocket server for tests"""

# Time fixtures
@pytest.fixture
def frozen_time():
    """Freeze time for deterministic tests"""
```

### 10.3 Mock Objects

**File:** `tests/mocks/storage_mock.py`

```python
class MockStorage:
    """Mock implementation of IGameStorage"""

    def __init__(self):
        self.saved_players = {}

    async def save_game(self, player):
        self.saved_players[player.userID] = player

    async def load_game(self, user_id):
        return self.saved_players.get(user_id)
```

**File:** `tests/mocks/output_mock.py`

```python
class MockOutput:
    """Mock implementation of IGameOutput"""

    def __init__(self):
        self.sent_messages = []

    async def send_event(self, player, event):
        self.sent_messages.append(('event', event))

    async def send_update(self, player, update):
        self.sent_messages.append(('update', update))
```

### 10.4 Test Utilities

**File:** `tests/utils/assertions.py`

```python
def assert_event_triggered(player, event_fname):
    """Assert event was triggered"""
    assert event_fname in player.events

def assert_stat_in_range(person, stat_name, min_val, max_val):
    """Assert stat is within range"""
    value = getattr(person, stat_name)
    assert min_val <= value <= max_val

def assert_relationship_exists(player, person_id):
    """Assert relationship exists"""
    assert any(r.id == person_id for r in player.r)

def assert_affinity_level(relationship, expected_level):
    """Assert affinity is at expected level"""
    if expected_level == "high":
        assert relationship.affinity >= 70
    elif expected_level == "medium":
        assert 40 <= relationship.affinity < 70
    elif expected_level == "low":
        assert relationship.affinity < 40
```

**File:** `tests/utils/factories.py`

```python
def create_test_player(**kwargs):
    """Factory for creating test players"""

def create_test_person(**kwargs):
    """Factory for creating test characters"""

def create_test_relationship(**kwargs):
    """Factory for creating test relationships"""

def create_test_event(**kwargs):
    """Factory for creating test events"""
```

### 10.5 CI/CD Integration

**File:** `.github/workflows/test.yml`

```yaml
name: Test Suite

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main, develop ]

jobs:
  test:
    runs-on: ubuntu-latest

    services:
      mysql:
        image: mysql:8.0
        env:
          MYSQL_ROOT_PASSWORD: testpass
          MYSQL_DATABASE: lifesim_test
        ports:
          - 3306:3306

    steps:
      - uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: |
          pip install -r requirements.txt
          pip install -r requirements-dev.txt

      - name: Run unit tests
        run: pytest tests/unit -v --cov

      - name: Run integration tests
        run: pytest tests/integration -v --cov --cov-append

      - name: Upload coverage
        uses: codecov/codecov-action@v3

      - name: Check coverage threshold
        run: pytest --cov --cov-fail-under=80
```

---

## 11. Implementation Roadmap

### Phase 1: Foundation (Week 1-2) - P0 Tests

**Goals:**
- Set up test infrastructure
- Implement critical path tests
- Achieve 40% coverage

**Tasks:**
1. Configure pytest, pytest-asyncio, pytest-cov
2. Create fixture library (conftest.py, player_fixtures.py)
3. Create mock objects (storage, output, services)
4. Implement core tests:
   - `test_game_engine.py` (30 tests)
   - `test_models.py` (40 tests)
   - `test_database_async.py` (30 tests)
   - `test_game_persistence.py` (30 tests)
   - `test_websocket_handlers.py` (20 tests)

**Deliverables:**
- 150 test cases
- 40% code coverage
- CI/CD pipeline configured

---

### Phase 2: Core Systems (Week 3-4) - P1 Tests

**Goals:**
- Test all major game systems
- Achieve 60% coverage

**Tasks:**
1. Implement event system tests:
   - `test_event_registry.py` (15 tests)
   - `test_event_handlers.py` (15 tests)
   - `test_event_base.py` (30 tests)
   - Event category tests (80 tests)
2. Implement game mechanics tests:
   - `test_stats_manager.py` (40 tests)
   - `test_character_manager.py` (35 tests)
   - `test_education_manager.py` (30 tests)
   - `test_job_manager.py` (25 tests)
   - `test_relationship_manager.py` (20 tests)
3. Implement WebSocket tests:
   - `test_websocket_messaging.py` (20 tests)
   - `test_command_dispatcher.py` (20 tests)

**Deliverables:**
- 330 additional test cases (480 total)
- 60% code coverage
- Integration tests passing

---

### Phase 3: Advanced Features (Week 5-6) - P2 Tests

**Goals:**
- Test remaining features
- Achieve 75% coverage

**Tasks:**
1. Implement health system tests:
   - `test_health_manager.py` (30 tests)
2. Implement dating system tests:
   - `test_dating_compatibility.py` (10 tests)
   - `test_dating_bio_generator.py` (5 tests)
   - `test_dating_matching.py` (5 tests)
   - `test_dating_activities.py` (5 tests)
3. Implement monetization tests:
   - `test_shop_manager.py` (10 tests)
   - `test_monetization.py` (10 tests)
4. Implement retention tests:
   - `test_daily_quests.py` (8 tests)
   - `test_daily_rewards.py` (8 tests)
   - `test_achievements.py` (6 tests)
   - `test_tutorial.py` (8 tests)
5. Implement integration tests:
   - `test_full_game_loop.py` (12 tests)
   - `test_multi_character.py` (10 tests)
   - `test_event_chains.py` (10 tests)

**Deliverables:**
- 137 additional test cases (617 total)
- 75% code coverage
- E2E tests passing

---

### Phase 4: Performance & Polish (Week 7+) - P3 Tests

**Goals:**
- Achieve 80%+ coverage
- Performance benchmarks
- Load testing

**Tasks:**
1. Implement E2E tests:
   - `test_websocket_e2e.py` (10 tests)
2. Implement load tests:
   - `test_websocket_load.py` (8 scenarios)
3. Implement performance benchmarks:
   - `test_benchmarks.py` (12 benchmarks)
4. Fill coverage gaps:
   - `test_utils.py` (25 tests)
   - Remaining edge cases (50 tests)
5. Property-based tests:
   - Use Hypothesis for stat calculations (20 tests)

**Deliverables:**
- 125 additional test cases (742 total)
- 80%+ code coverage
- Performance baseline established
- Load testing results documented

---

### Phase 5: Continuous Improvement (Ongoing)

**Goals:**
- Maintain coverage
- Add tests for new features
- Fix flaky tests

**Tasks:**
1. Regression tests for every bug fix
2. Tests for every new feature
3. Regular coverage audits
4. Performance regression detection
5. Test suite optimization (reduce flakiness)

---

## 12. Success Metrics

### 12.1 Coverage Targets

| Category | Target Coverage |
|----------|----------------|
| **Overall** | **80%+** |
| Core game loop | 95%+ |
| Event system | 85%+ |
| Database operations | 90%+ |
| WebSocket handlers | 85%+ |
| Game mechanics | 80%+ |
| Character management | 85%+ |
| Stats calculations | 90%+ |
| Health system | 75%+ |
| Dating system | 70%+ |
| Monetization | 80%+ |
| Utilities | 70%+ |

### 12.2 Quality Metrics

**Test Suite Performance:**
- Unit tests: Average < 100ms per test
- Integration tests: Average < 1s per test
- E2E tests: Average < 10s per test
- Total suite time: < 10 minutes

**Test Reliability:**
- Flaky test rate: < 1%
- Test failure false positive rate: < 2%
- Test suite stability: 99%+ consistent results

**Development Metrics:**
- Time to run unit tests: < 1 minute
- Time to run all tests: < 10 minutes
- CI/CD pipeline time: < 15 minutes
- Coverage report generation: < 1 minute

### 12.3 Documentation

**Required Documentation:**
- [ ] Testing guide for new developers
- [ ] Fixture library documentation
- [ ] Mock object usage guide
- [ ] CI/CD pipeline documentation
- [ ] Coverage reports (auto-generated)
- [ ] Performance benchmarks (tracked over time)
- [ ] Test naming conventions
- [ ] Test organization structure

---

## 13. Test File Structure

```
tests/
├── conftest.py                          # Global fixtures
├── pytest.ini                           # Pytest configuration
│
├── fixtures/
│   ├── player_fixtures.py              # Player test data
│   ├── scenario_fixtures.py            # Game scenarios
│   └── database_fixtures.py            # Database fixtures
│
├── mocks/
│   ├── storage_mock.py                 # Storage layer mock
│   ├── output_mock.py                  # Output layer mock
│   ├── services_mock.py                # Service mocks
│   └── time_mock.py                    # Time mocking utilities
│
├── utils/
│   ├── assertions.py                   # Custom assertions
│   ├── factories.py                    # Test data factories
│   └── helpers.py                      # Test helper functions
│
├── unit/                                # Unit tests (60%)
│   ├── test_game_engine.py             # 30 tests - P0
│   ├── test_models.py                  # 40 tests - P0
│   ├── test_stats_manager.py           # 40 tests - P1
│   ├── test_character_manager.py       # 35 tests - P1
│   ├── test_education_manager.py       # 30 tests - P1
│   ├── test_job_manager.py             # 25 tests - P1
│   ├── test_health_manager.py          # 30 tests - P2
│   ├── test_relationship_manager.py    # 20 tests - P1
│   ├── test_event_registry.py          # 15 tests - P1
│   ├── test_event_handlers.py          # 15 tests - P1
│   ├── test_event_base.py              # 30 tests - P1
│   ├── test_websocket_messaging.py     # 20 tests - P1
│   ├── test_command_dispatcher.py      # 20 tests - P1
│   ├── test_shop_manager.py            # 10 tests - P2
│   ├── test_monetization.py            # 10 tests - P2
│   ├── test_daily_quests.py            # 8 tests - P2
│   ├── test_daily_rewards.py           # 8 tests - P2
│   ├── test_achievements.py            # 6 tests - P2
│   ├── test_tutorial.py                # 8 tests - P2
│   ├── test_utils.py                   # 25 tests - P3
│   │
│   ├── events/                          # Event category tests
│   │   ├── test_childhood_events.py    # 12 tests - P1
│   │   ├── test_adolescence_events.py  # 12 tests - P1
│   │   ├── test_education_events.py    # 10 tests - P1
│   │   ├── test_adulthood_events.py    # 12 tests - P1
│   │   ├── test_health_events.py       # 10 tests - P2
│   │   ├── test_holiday_events.py      # 8 tests - P2
│   │   ├── test_random_events.py       # 8 tests - P2
│   │   └── test_dilemmas.py            # 8 tests - P2
│   │
│   └── dating/                          # Dating system tests
│       ├── test_dating_compatibility.py # 10 tests - P2
│       ├── test_dating_bio_generator.py # 5 tests - P2
│       ├── test_dating_matching.py      # 5 tests - P2
│       └── test_dating_activities.py    # 5 tests - P2
│
├── integration/                         # Integration tests (30%)
│   ├── test_database_async.py          # 30 tests - P0
│   ├── test_game_persistence.py        # 30 tests - P0
│   ├── test_websocket_handlers.py      # 20 tests - P0
│   ├── test_full_game_loop.py          # 12 tests - P2
│   ├── test_multi_character.py         # 10 tests - P2
│   ├── test_event_chains.py            # 10 tests - P2
│   └── test_migrations.py              # 8 tests - P1
│
├── e2e/                                 # End-to-end tests (10%)
│   └── test_websocket_e2e.py           # 10 tests - P3
│
├── load/                                # Load tests
│   └── test_websocket_load.py          # 8 scenarios - P3
│
├── performance/                         # Performance tests
│   └── test_benchmarks.py              # 12 benchmarks - P3
│
└── property/                            # Property-based tests
    ├── test_stat_calculations.py       # 10 tests - P3
    └── test_time_progression.py        # 10 tests - P3
```

**Total Estimated Tests:** ~742 test cases

---

## 14. Testing Best Practices

### 14.1 Test Naming Convention

Use descriptive names following the pattern:
```
test_<system>_<behavior>_<condition>
```

Examples:
- `test_game_tick_increments_time_by_one_minute()`
- `test_question_event_pauses_game_when_triggered()`
- `test_save_game_fails_gracefully_when_database_unavailable()`

### 14.2 Test Structure (Arrange-Act-Assert)

```python
def test_energy_depletion_during_activity():
    # Arrange
    player = create_test_player()
    player.c.energy = 100
    player.c.dailyPlan = [create_running_activity()]

    # Act
    game_engine.run_game_tick_sync(player)

    # Assert
    assert player.c.energy < 100
    assert player.c.energy > 0
```

### 14.3 Mocking Strategy

**Mock external dependencies:**
- Database calls
- WebSocket connections
- API calls (OpenAI, image generation)
- Time-based functions

**Don't mock:**
- Internal business logic
- Simple data structures
- Utility functions

### 14.4 Test Data Management

**Use fixtures for:**
- Common test scenarios
- Database setup/teardown
- Mock object creation

**Use factories for:**
- Creating test objects with variations
- Generating random test data

### 14.5 Async Testing

```python
@pytest.mark.asyncio
async def test_async_save_game():
    player = create_test_player()
    await save_game_async(player)
    loaded = await load_game_async(player.userID)
    assert loaded.userID == player.userID
```

### 14.6 Database Testing

**Use transactions for isolation:**
```python
@pytest.fixture
async def db_transaction():
    async with Transaction() as txn:
        yield txn
        await txn.rollback()
```

### 14.7 Flaky Test Prevention

**Avoid:**
- Hardcoded time values (use mocking)
- Race conditions (use proper async/await)
- Random data without seeds
- External API dependencies

**Use:**
- Deterministic test data
- Time mocking for time-based tests
- Proper async synchronization
- Retry logic only for I/O operations

---

## 15. Dependencies & Tools

### 15.1 Testing Dependencies

Add to `requirements-dev.txt`:

```txt
# Testing Framework
pytest==7.4.3
pytest-asyncio==0.21.1
pytest-cov==4.1.0
pytest-mock==3.12.0
pytest-timeout==2.2.0
pytest-xdist==3.5.0  # Parallel test execution
pytest-benchmark==4.0.0

# Property-Based Testing
hypothesis==6.92.1

# Load Testing
locust==2.18.3

# Test Utilities
freezegun==1.4.0  # Time mocking
faker==20.1.0  # Test data generation
factory-boy==3.3.0  # Test factories

# Coverage
coverage[toml]==7.4.0
codecov==2.1.13

# Linting (for test code)
pytest-pylint==0.21.0
pytest-flake8==1.1.1
```

### 15.2 Development Tools

```bash
# Run all tests
pytest

# Run with coverage
pytest --cov=ws --cov-report=html

# Run specific test file
pytest tests/unit/test_game_engine.py

# Run specific test
pytest tests/unit/test_game_engine.py::test_time_progression_single_minute

# Run tests matching pattern
pytest -k "game_tick"

# Run tests in parallel
pytest -n auto

# Run with verbose output
pytest -v

# Run only unit tests
pytest tests/unit -m unit

# Run only integration tests
pytest tests/integration -m integration

# Generate coverage report
pytest --cov=ws --cov-report=html
open htmlcov/index.html

# Run with benchmarking
pytest --benchmark-only

# Run load tests
locust -f tests/load/test_websocket_load.py
```

---

## 16. Risk Mitigation

### 16.1 Common Testing Challenges

| Challenge | Mitigation |
|-----------|------------|
| **Flaky Tests** | Use time mocking, deterministic data, proper async/await |
| **Slow Tests** | Mock I/O, use parallel execution, optimize fixtures |
| **Complex Game State** | Use factories, fixtures, helper functions |
| **Database State** | Use transactions, clean up after tests |
| **WebSocket Testing** | Use test client, mock connections |
| **Time-Based Logic** | Use freezegun or time mocking |
| **Random Events** | Seed random number generators |
| **Coverage Gaps** | Regular audits, coverage ratcheting |

### 16.2 Test Maintenance

**Regular Tasks:**
- [ ] Review and update fixtures quarterly
- [ ] Audit flaky tests monthly
- [ ] Optimize slow tests monthly
- [ ] Update mocks when interfaces change
- [ ] Review coverage reports weekly
- [ ] Clean up obsolete tests
- [ ] Update documentation

---

## 17. Next Steps After Planning

1. **Review this plan** with the team
2. **Set up test infrastructure** (Phase 1, Week 1)
3. **Create first 20 tests** to validate approach
4. **Iterate and refine** based on learnings
5. **Begin Phase 1 implementation** following roadmap
6. **Track progress** against coverage goals
7. **Adjust timeline** as needed

---

## Appendix A: Quick Reference

### Running Tests

```bash
# Quick test commands
pytest                              # Run all tests
pytest tests/unit                   # Unit tests only
pytest tests/integration            # Integration tests only
pytest -m "not slow"               # Skip slow tests
pytest --cov                        # With coverage
pytest -n auto                      # Parallel execution
pytest -k "game_tick"              # Pattern matching
pytest -v                           # Verbose output
pytest --lf                         # Last failed
pytest --ff                         # Failed first
```

### Coverage Commands

```bash
# Coverage commands
pytest --cov=ws                     # Basic coverage
pytest --cov=ws --cov-report=html  # HTML report
pytest --cov=ws --cov-report=term-missing  # Terminal with missing lines
pytest --cov-fail-under=80         # Fail if < 80%
coverage html                       # Generate HTML report
```

### Test Markers

```python
@pytest.mark.unit              # Unit test
@pytest.mark.integration       # Integration test
@pytest.mark.e2e              # End-to-end test
@pytest.mark.slow             # Slow test (> 1s)
@pytest.mark.db               # Requires database
@pytest.mark.websocket        # Requires WebSocket
@pytest.mark.asyncio          # Async test
```

---

## Appendix B: Coverage Calculation

**Total Lines of Code:** ~34,278 (estimated from core modules)

**Coverage Targets:**
- Phase 1: 40% = ~13,711 lines covered = ~150 tests
- Phase 2: 60% = ~20,567 lines covered = ~480 tests
- Phase 3: 75% = ~25,709 lines covered = ~617 tests
- Phase 4: 80% = ~27,422 lines covered = ~742 tests

**Estimated Test-to-Code Ratio:** 1 test per ~37 lines of code

---

## Document Control

| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 1.0 | 2025-11-14 | Claude Code | Initial comprehensive testing plan |

**Review Schedule:** Quarterly
**Next Review:** 2026-02-14
**Owner:** Development Team

---

**End of Testing Plan**
