paper-dynasty-gameplay-webapp/tests/demo_data_isolation.py
Cal Corum 559fe73f07 CLAUDE: Complete Player model migration with service layer and integration test infrastructure
## Player Model Migration
- Migrate Player model from Discord app following Model/Service Architecture pattern
- Extract all business logic from Player model to PlayerService
- Create pure data model with PostgreSQL relationships (Cardset, PositionRating)
- Implement comprehensive PlayerFactory with specialized methods for test data

## PlayerService Implementation
- Extract 5 business logic methods from original Player model:
  - get_batter_card_url() - batting card URL retrieval
  - get_pitcher_card_url() - pitching card URL retrieval
  - generate_name_card_link() - markdown link generation
  - get_formatted_name_with_description() - name formatting
  - get_player_description() - description from object or dict
- Follow BaseService pattern with dependency injection and logging

## Comprehensive Testing
- 35 passing Player tests (14 model + 21 service tests)
- PlayerFactory with specialized methods (batting/pitching cards, positions)
- Test isolation following factory pattern and db_session guidelines
- Fix PostgreSQL integer overflow in test ID generation

## Integration Test Infrastructure
- Create integration test framework for improving service coverage
- Design AIService integration tests targeting uncovered branches
- Demonstrate real database query testing with proper isolation
- Establish patterns for testing complex game scenarios

## Service Coverage Analysis
- Current service coverage: 61% overall
- PlayerService: 100% coverage (excellent migration example)
- AIService: 60% coverage (improvement opportunities identified)
- Integration test strategy designed to achieve 90%+ coverage

## Database Integration
- Update Cardset model to include players relationship
- Update PositionRating model with proper Player foreign key
- Maintain all existing relationships and constraints
- Demonstrate data isolation and automatic cleanup in tests

## Test Suite Status
- 137 tests passing, 0 failures (maintained 100% pass rate)
- Added 35 new tests while preserving all existing functionality
- Integration test infrastructure ready for coverage improvements

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-29 16:20:29 -05:00

116 lines
4.7 KiB
Python

"""
Demonstration of data isolation in tests.
This shows how our test infrastructure prevents data interference between tests.
"""
import pytest
from sqlmodel import select
from app.models.player import Player
from tests.factories.player_factory import PlayerFactory
class TestDataIsolationDemo:
"""Demonstrate how data isolation works between tests."""
def test_first_creates_player(self, db_session):
"""First test creates a player - this data should not affect other tests."""
# Create player with specific name
player = PlayerFactory.create(db_session, name="Test Player Alpha", cost=100)
# Verify it exists in this test's transaction
result = db_session.exec(select(Player).where(Player.name == "Test Player Alpha")).first()
assert result is not None
assert result.cost == 100
print(f"Created player with ID: {player.id} in first test")
def test_second_cannot_see_first_player(self, db_session):
"""Second test runs in separate transaction - cannot see first test's data."""
# Try to find the player from the first test
result = db_session.exec(select(Player).where(Player.name == "Test Player Alpha")).first()
# Should be None because first test's transaction was rolled back
assert result is None
# Create our own player with same name but different cost
player = PlayerFactory.create(db_session, name="Test Player Alpha", cost=200)
assert player.cost == 200
print(f"Cannot see first test's player - created new one with ID: {player.id}")
def test_third_also_isolated(self, db_session):
"""Third test is also completely isolated from previous tests."""
# Should not see players from either previous test
results = db_session.exec(select(Player).where(Player.name == "Test Player Alpha")).all()
assert len(results) == 0
# Can create multiple players without conflict
player1 = PlayerFactory.create(db_session, name="Test Player Alpha", cost=300)
player2 = PlayerFactory.create(db_session, name="Test Player Beta", cost=400)
# Both exist in this test's transaction
all_results = db_session.exec(select(Player)).all()
assert len(all_results) == 2
print(f"Third test: created players with IDs {player1.id} and {player2.id}")
class TestDataIsolationWithFreshSession:
"""Demonstrate fresh_db_session behavior (real commits)."""
def test_with_fresh_session_persists_data(self, fresh_db_session):
"""Test using fresh_db_session - data actually commits to test database."""
# Create player with real commit
player = PlayerFactory.create(fresh_db_session, name="Persistent Player", cost=500)
fresh_db_session.commit() # Real commit to test database
# Verify it's committed
fresh_db_session.refresh(player)
assert player.id is not None
print(f"Committed player with ID: {player.id} to test database")
# Manual cleanup for this demonstration
fresh_db_session.delete(player)
fresh_db_session.commit()
print("Manually cleaned up persistent player")
def test_after_fresh_session_cleanup(self, db_session):
"""This test should not see the fresh session data (it was cleaned up)."""
result = db_session.exec(select(Player).where(Player.name == "Persistent Player")).first()
assert result is None
print("Confirmed: Fresh session data was properly cleaned up")
class TestDataIsolationFactories:
"""Demonstrate how factories prevent ID conflicts."""
def test_factory_generates_unique_ids(self, db_session):
"""Factories generate unique IDs to prevent conflicts."""
# Create multiple players - factories ensure unique IDs
players = [
PlayerFactory.create(db_session, name=f"Player {i}")
for i in range(5)
]
# All should have different IDs
player_ids = [p.id for p in players]
assert len(set(player_ids)) == 5 # All unique
print(f"Generated unique IDs: {player_ids}")
def test_can_create_same_names_different_ids(self, db_session):
"""Different tests can create objects with same names but different IDs."""
# This won't conflict with previous test because transaction is isolated
players = [
PlayerFactory.create(db_session, name="Player 1"),
PlayerFactory.create(db_session, name="Player 2"),
]
# IDs will be different from previous test
print(f"Same names, different IDs: {[p.id for p in players]}")
# Names can be the same across tests, IDs will always be unique
assert players[0].name == "Player 1"
assert players[1].name == "Player 2"