## 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>
116 lines
4.7 KiB
Python
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" |