fix: remove unimplementable skipped caching tests (#33)

The three skipped tests in TestPlayerServiceCache required caching
in get_players() (read-through cache) and cache propagation through
the cls() pattern in write methods — neither is implemented and the
architecture does not support it without significant refactoring.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Cal Corum 2026-03-06 10:33:19 -06:00
parent 95ff5eeaf9
commit c40426d175

View File

@ -7,21 +7,18 @@ import pytest
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
import sys import sys
import os import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from app.services.player_service import PlayerService from app.services.player_service import PlayerService
from app.services.base import ServiceConfig from app.services.base import ServiceConfig
from app.services.mocks import ( from app.services.mocks import MockPlayerRepository, MockCacheService, EnhancedMockCache
MockPlayerRepository,
MockCacheService,
EnhancedMockCache
)
# ============================================================================ # ============================================================================
# FIXTURES # FIXTURES
# ============================================================================ # ============================================================================
@pytest.fixture @pytest.fixture
def cache(): def cache():
"""Create fresh cache for each test.""" """Create fresh cache for each test."""
@ -32,20 +29,73 @@ def cache():
def repo(cache): def repo(cache):
"""Create fresh repo with test data.""" """Create fresh repo with test data."""
repo = MockPlayerRepository() repo = MockPlayerRepository()
# Add test players # Add test players
players = [ players = [
{'id': 1, 'name': 'Mike Trout', 'wara': 5.2, 'team_id': 1, 'season': 10, 'pos_1': 'CF', 'pos_2': 'LF', 'strat_code': 'Elite', 'injury_rating': 'A'}, {
{'id': 2, 'name': 'Aaron Judge', 'wara': 4.8, 'team_id': 2, 'season': 10, 'pos_1': 'RF', 'strat_code': 'Power', 'injury_rating': 'B'}, "id": 1,
{'id': 3, 'name': 'Mookie Betts', 'wara': 5.5, 'team_id': 3, 'season': 10, 'pos_1': 'RF', 'pos_2': '2B', 'strat_code': 'Elite', 'injury_rating': 'A'}, "name": "Mike Trout",
{'id': 4, 'name': 'Injured Player', 'wara': 2.0, 'team_id': 1, 'season': 10, 'pos_1': 'P', 'il_return': 'Week 5', 'injury_rating': 'C'}, "wara": 5.2,
{'id': 5, 'name': 'Old Player', 'wara': 1.0, 'team_id': 1, 'season': 5, 'pos_1': '1B'}, "team_id": 1,
{'id': 6, 'name': 'Juan Soto', 'wara': 4.5, 'team_id': 2, 'season': 10, 'pos_1': '1B', 'strat_code': 'Contact'}, "season": 10,
"pos_1": "CF",
"pos_2": "LF",
"strat_code": "Elite",
"injury_rating": "A",
},
{
"id": 2,
"name": "Aaron Judge",
"wara": 4.8,
"team_id": 2,
"season": 10,
"pos_1": "RF",
"strat_code": "Power",
"injury_rating": "B",
},
{
"id": 3,
"name": "Mookie Betts",
"wara": 5.5,
"team_id": 3,
"season": 10,
"pos_1": "RF",
"pos_2": "2B",
"strat_code": "Elite",
"injury_rating": "A",
},
{
"id": 4,
"name": "Injured Player",
"wara": 2.0,
"team_id": 1,
"season": 10,
"pos_1": "P",
"il_return": "Week 5",
"injury_rating": "C",
},
{
"id": 5,
"name": "Old Player",
"wara": 1.0,
"team_id": 1,
"season": 5,
"pos_1": "1B",
},
{
"id": 6,
"name": "Juan Soto",
"wara": 4.5,
"team_id": 2,
"season": 10,
"pos_1": "1B",
"strat_code": "Contact",
},
] ]
for player in players: for player in players:
repo.add_player(player) repo.add_player(player)
return repo return repo
@ -60,463 +110,453 @@ def service(repo, cache):
# TEST CLASSES # TEST CLASSES
# ============================================================================ # ============================================================================
class TestPlayerServiceGetPlayers: class TestPlayerServiceGetPlayers:
"""Tests for get_players method - 50+ lines covered.""" """Tests for get_players method - 50+ lines covered."""
def test_get_all_season_players(self, service, repo): def test_get_all_season_players(self, service, repo):
"""Get all players for a season.""" """Get all players for a season."""
result = service.get_players(season=10) result = service.get_players(season=10)
assert result['count'] >= 5 # We have 5 season 10 players assert result["count"] >= 5 # We have 5 season 10 players
assert len(result['players']) >= 5 assert len(result["players"]) >= 5
assert all(p.get('season') == 10 for p in result['players']) assert all(p.get("season") == 10 for p in result["players"])
def test_filter_by_single_team(self, service): def test_filter_by_single_team(self, service):
"""Filter by single team ID.""" """Filter by single team ID."""
result = service.get_players(season=10, team_id=[1]) result = service.get_players(season=10, team_id=[1])
assert result['count'] >= 1 assert result["count"] >= 1
assert all(p.get('team_id') == 1 for p in result['players']) assert all(p.get("team_id") == 1 for p in result["players"])
def test_filter_by_multiple_teams(self, service): def test_filter_by_multiple_teams(self, service):
"""Filter by multiple team IDs.""" """Filter by multiple team IDs."""
result = service.get_players(season=10, team_id=[1, 2]) result = service.get_players(season=10, team_id=[1, 2])
assert result['count'] >= 2 assert result["count"] >= 2
assert all(p.get('team_id') in [1, 2] for p in result['players']) assert all(p.get("team_id") in [1, 2] for p in result["players"])
def test_filter_by_position(self, service): def test_filter_by_position(self, service):
"""Filter by position.""" """Filter by position."""
result = service.get_players(season=10, pos=['CF']) result = service.get_players(season=10, pos=["CF"])
assert result['count'] >= 1 assert result["count"] >= 1
assert any(p.get('pos_1') == 'CF' or p.get('pos_2') == 'CF' for p in result['players']) assert any(
p.get("pos_1") == "CF" or p.get("pos_2") == "CF" for p in result["players"]
)
def test_filter_by_strat_code(self, service): def test_filter_by_strat_code(self, service):
"""Filter by strat code.""" """Filter by strat code."""
result = service.get_players(season=10, strat_code=['Elite']) result = service.get_players(season=10, strat_code=["Elite"])
assert result['count'] >= 2 # Trout and Betts assert result["count"] >= 2 # Trout and Betts
assert all('Elite' in str(p.get('strat_code', '')) for p in result['players']) assert all("Elite" in str(p.get("strat_code", "")) for p in result["players"])
def test_filter_injured_only(self, service): def test_filter_injured_only(self, service):
"""Filter injured players only.""" """Filter injured players only."""
result = service.get_players(season=10, is_injured=True) result = service.get_players(season=10, is_injured=True)
assert result['count'] >= 1 assert result["count"] >= 1
assert all(p.get('il_return') is not None for p in result['players']) assert all(p.get("il_return") is not None for p in result["players"])
def test_sort_cost_ascending(self, service): def test_sort_cost_ascending(self, service):
"""Sort by WARA ascending.""" """Sort by WARA ascending."""
result = service.get_players(season=10, sort='cost-asc') result = service.get_players(season=10, sort="cost-asc")
wara = [p.get('wara', 0) for p in result['players']] wara = [p.get("wara", 0) for p in result["players"]]
assert wara == sorted(wara) assert wara == sorted(wara)
def test_sort_cost_descending(self, service): def test_sort_cost_descending(self, service):
"""Sort by WARA descending.""" """Sort by WARA descending."""
result = service.get_players(season=10, sort='cost-desc') result = service.get_players(season=10, sort="cost-desc")
wara = [p.get('wara', 0) for p in result['players']] wara = [p.get("wara", 0) for p in result["players"]]
assert wara == sorted(wara, reverse=True) assert wara == sorted(wara, reverse=True)
def test_sort_name_ascending(self, service): def test_sort_name_ascending(self, service):
"""Sort by name ascending.""" """Sort by name ascending."""
result = service.get_players(season=10, sort='name-asc') result = service.get_players(season=10, sort="name-asc")
names = [p.get('name', '') for p in result['players']] names = [p.get("name", "") for p in result["players"]]
assert names == sorted(names) assert names == sorted(names)
def test_sort_name_descending(self, service): def test_sort_name_descending(self, service):
"""Sort by name descending.""" """Sort by name descending."""
result = service.get_players(season=10, sort='name-desc') result = service.get_players(season=10, sort="name-desc")
names = [p.get('name', '') for p in result['players']] names = [p.get("name", "") for p in result["players"]]
assert names == sorted(names, reverse=True) assert names == sorted(names, reverse=True)
class TestPlayerServiceSearch: class TestPlayerServiceSearch:
"""Tests for search_players method.""" """Tests for search_players method."""
def test_exact_name_match(self, service): def test_exact_name_match(self, service):
"""Search with exact name match.""" """Search with exact name match."""
result = service.search_players('Mike Trout', season=10) result = service.search_players("Mike Trout", season=10)
assert result['count'] >= 1 assert result["count"] >= 1
names = [p.get('name') for p in result['players']] names = [p.get("name") for p in result["players"]]
assert 'Mike Trout' in names assert "Mike Trout" in names
def test_partial_name_match(self, service): def test_partial_name_match(self, service):
"""Search with partial name match.""" """Search with partial name match."""
result = service.search_players('Trout', season=10) result = service.search_players("Trout", season=10)
assert result['count'] >= 1 assert result["count"] >= 1
assert any('Trout' in p.get('name', '') for p in result['players']) assert any("Trout" in p.get("name", "") for p in result["players"])
def test_case_insensitive_search(self, service): def test_case_insensitive_search(self, service):
"""Search is case insensitive.""" """Search is case insensitive."""
result1 = service.search_players('MIKE', season=10) result1 = service.search_players("MIKE", season=10)
result2 = service.search_players('mike', season=10) result2 = service.search_players("mike", season=10)
assert result1['count'] == result2['count'] assert result1["count"] == result2["count"]
def test_search_all_seasons(self, service): def test_search_all_seasons(self, service):
"""Search across all seasons.""" """Search across all seasons."""
result = service.search_players('Player', season=None) result = service.search_players("Player", season=None)
# Should find both current and old players # Should find both current and old players
assert result['all_seasons'] == True assert result["all_seasons"] == True
assert result['count'] >= 2 assert result["count"] >= 2
def test_search_limit(self, service): def test_search_limit(self, service):
"""Limit search results.""" """Limit search results."""
result = service.search_players('a', season=10, limit=2) result = service.search_players("a", season=10, limit=2)
assert result['count'] <= 2 assert result["count"] <= 2
def test_search_no_results(self, service): def test_search_no_results(self, service):
"""Search returns empty when no matches.""" """Search returns empty when no matches."""
result = service.search_players('XYZ123NotExist', season=10) result = service.search_players("XYZ123NotExist", season=10)
assert result['count'] == 0 assert result["count"] == 0
assert result['players'] == [] assert result["players"] == []
class TestPlayerServiceGetPlayer: class TestPlayerServiceGetPlayer:
"""Tests for get_player method.""" """Tests for get_player method."""
def test_get_existing_player(self, service): def test_get_existing_player(self, service):
"""Get existing player by ID.""" """Get existing player by ID."""
result = service.get_player(1) result = service.get_player(1)
assert result is not None assert result is not None
assert result.get('id') == 1 assert result.get("id") == 1
assert result.get('name') == 'Mike Trout' assert result.get("name") == "Mike Trout"
def test_get_nonexistent_player(self, service): def test_get_nonexistent_player(self, service):
"""Get player that doesn't exist.""" """Get player that doesn't exist."""
result = service.get_player(99999) result = service.get_player(99999)
assert result is None assert result is None
def test_get_player_short_output(self, service): def test_get_player_short_output(self, service):
"""Get player with short output.""" """Get player with short output."""
result = service.get_player(1, short_output=True) result = service.get_player(1, short_output=True)
# Should still have basic fields # Should still have basic fields
assert result.get('id') == 1 assert result.get("id") == 1
assert result.get('name') == 'Mike Trout' assert result.get("name") == "Mike Trout"
class TestPlayerServiceCreate: class TestPlayerServiceCreate:
"""Tests for create_players method.""" """Tests for create_players method."""
def test_create_single_player(self, repo, cache): def test_create_single_player(self, repo, cache):
"""Create a single new player.""" """Create a single new player."""
config = ServiceConfig(player_repo=repo, cache=cache) config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config) service = PlayerService(config=config)
new_player = [{ new_player = [
'name': 'New Player', {
'wara': 3.0, "name": "New Player",
'team_id': 1, "wara": 3.0,
'season': 10, "team_id": 1,
'pos_1': 'SS' "season": 10,
}] "pos_1": "SS",
}
]
# Mock auth # Mock auth
with patch.object(service, 'require_auth', return_value=True): with patch.object(service, "require_auth", return_value=True):
result = service.create_players(new_player, 'valid_token') result = service.create_players(new_player, "valid_token")
assert 'Inserted' in str(result) assert "Inserted" in str(result)
# Verify player was added (ID 7 since fixture has players 1-6) # Verify player was added (ID 7 since fixture has players 1-6)
player = repo.get_by_id(7) # Next ID after fixture data player = repo.get_by_id(7) # Next ID after fixture data
assert player is not None assert player is not None
assert player['name'] == 'New Player' assert player["name"] == "New Player"
def test_create_multiple_players(self, repo, cache): def test_create_multiple_players(self, repo, cache):
"""Create multiple new players.""" """Create multiple new players."""
config = ServiceConfig(player_repo=repo, cache=cache) config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config) service = PlayerService(config=config)
new_players = [ new_players = [
{'name': 'Player A', 'wara': 2.0, 'team_id': 1, 'season': 10, 'pos_1': '2B'}, {
{'name': 'Player B', 'wara': 2.5, 'team_id': 2, 'season': 10, 'pos_1': '3B'}, "name": "Player A",
"wara": 2.0,
"team_id": 1,
"season": 10,
"pos_1": "2B",
},
{
"name": "Player B",
"wara": 2.5,
"team_id": 2,
"season": 10,
"pos_1": "3B",
},
] ]
with patch.object(service, 'require_auth', return_value=True): with patch.object(service, "require_auth", return_value=True):
result = service.create_players(new_players, 'valid_token') result = service.create_players(new_players, "valid_token")
assert 'Inserted 2 players' in str(result) assert "Inserted 2 players" in str(result)
def test_create_duplicate_fails(self, repo, cache): def test_create_duplicate_fails(self, repo, cache):
"""Creating duplicate player should fail.""" """Creating duplicate player should fail."""
config = ServiceConfig(player_repo=repo, cache=cache) config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config) service = PlayerService(config=config)
duplicate = [{'name': 'Mike Trout', 'wara': 5.0, 'team_id': 1, 'season': 10, 'pos_1': 'CF'}] duplicate = [
{
with patch.object(service, 'require_auth', return_value=True): "name": "Mike Trout",
"wara": 5.0,
"team_id": 1,
"season": 10,
"pos_1": "CF",
}
]
with patch.object(service, "require_auth", return_value=True):
with pytest.raises(Exception) as exc_info: with pytest.raises(Exception) as exc_info:
service.create_players(duplicate, 'valid_token') service.create_players(duplicate, "valid_token")
assert 'already exists' in str(exc_info.value) assert "already exists" in str(exc_info.value)
def test_create_requires_auth(self, repo, cache): def test_create_requires_auth(self, repo, cache):
"""Creating players requires authentication.""" """Creating players requires authentication."""
config = ServiceConfig(player_repo=repo, cache=cache) config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config) service = PlayerService(config=config)
new_player = [{'name': 'Test', 'wara': 1.0, 'team_id': 1, 'season': 10, 'pos_1': 'P'}] new_player = [
{"name": "Test", "wara": 1.0, "team_id": 1, "season": 10, "pos_1": "P"}
]
with pytest.raises(Exception) as exc_info: with pytest.raises(Exception) as exc_info:
service.create_players(new_player, 'bad_token') service.create_players(new_player, "bad_token")
assert exc_info.value.status_code == 401 assert exc_info.value.status_code == 401
class TestPlayerServiceUpdate: class TestPlayerServiceUpdate:
"""Tests for update_player and patch_player methods.""" """Tests for update_player and patch_player methods."""
def test_patch_player_name(self, repo, cache): def test_patch_player_name(self, repo, cache):
"""Patch player's name.""" """Patch player's name."""
config = ServiceConfig(player_repo=repo, cache=cache) config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config) service = PlayerService(config=config)
with patch.object(service, 'require_auth', return_value=True): with patch.object(service, "require_auth", return_value=True):
result = service.patch_player(1, {'name': 'New Name'}, 'valid_token') result = service.patch_player(1, {"name": "New Name"}, "valid_token")
assert result is not None assert result is not None
assert result.get('name') == 'New Name' assert result.get("name") == "New Name"
def test_patch_player_wara(self, repo, cache): def test_patch_player_wara(self, repo, cache):
"""Patch player's WARA.""" """Patch player's WARA."""
config = ServiceConfig(player_repo=repo, cache=cache) config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config) service = PlayerService(config=config)
with patch.object(service, 'require_auth', return_value=True): with patch.object(service, "require_auth", return_value=True):
result = service.patch_player(1, {'wara': 6.0}, 'valid_token') result = service.patch_player(1, {"wara": 6.0}, "valid_token")
assert result.get('wara') == 6.0 assert result.get("wara") == 6.0
def test_patch_multiple_fields(self, repo, cache): def test_patch_multiple_fields(self, repo, cache):
"""Patch multiple fields at once.""" """Patch multiple fields at once."""
config = ServiceConfig(player_repo=repo, cache=cache) config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config) service = PlayerService(config=config)
updates = { updates = {"name": "Updated Name", "wara": 7.0, "strat_code": "Super Elite"}
'name': 'Updated Name',
'wara': 7.0, with patch.object(service, "require_auth", return_value=True):
'strat_code': 'Super Elite' result = service.patch_player(1, updates, "valid_token")
}
assert result.get("name") == "Updated Name"
with patch.object(service, 'require_auth', return_value=True): assert result.get("wara") == 7.0
result = service.patch_player(1, updates, 'valid_token') assert result.get("strat_code") == "Super Elite"
assert result.get('name') == 'Updated Name'
assert result.get('wara') == 7.0
assert result.get('strat_code') == 'Super Elite'
def test_patch_nonexistent_player(self, repo, cache): def test_patch_nonexistent_player(self, repo, cache):
"""Patch fails for non-existent player.""" """Patch fails for non-existent player."""
config = ServiceConfig(player_repo=repo, cache=cache) config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config) service = PlayerService(config=config)
with patch.object(service, 'require_auth', return_value=True): with patch.object(service, "require_auth", return_value=True):
with pytest.raises(Exception) as exc_info: with pytest.raises(Exception) as exc_info:
service.patch_player(99999, {'name': 'Test'}, 'valid_token') service.patch_player(99999, {"name": "Test"}, "valid_token")
assert 'not found' in str(exc_info.value) assert "not found" in str(exc_info.value)
def test_patch_requires_auth(self, repo, cache): def test_patch_requires_auth(self, repo, cache):
"""Patching requires authentication.""" """Patching requires authentication."""
config = ServiceConfig(player_repo=repo, cache=cache) config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config) service = PlayerService(config=config)
with pytest.raises(Exception) as exc_info: with pytest.raises(Exception) as exc_info:
service.patch_player(1, {'name': 'Test'}, 'bad_token') service.patch_player(1, {"name": "Test"}, "bad_token")
assert exc_info.value.status_code == 401 assert exc_info.value.status_code == 401
class TestPlayerServiceDelete: class TestPlayerServiceDelete:
"""Tests for delete_player method.""" """Tests for delete_player method."""
def test_delete_player(self, repo, cache): def test_delete_player(self, repo, cache):
"""Delete existing player.""" """Delete existing player."""
config = ServiceConfig(player_repo=repo, cache=cache) config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config) service = PlayerService(config=config)
# Verify player exists # Verify player exists
assert repo.get_by_id(1) is not None assert repo.get_by_id(1) is not None
with patch.object(service, 'require_auth', return_value=True): with patch.object(service, "require_auth", return_value=True):
result = service.delete_player(1, 'valid_token') result = service.delete_player(1, "valid_token")
assert 'deleted' in str(result) assert "deleted" in str(result)
# Verify player is gone # Verify player is gone
assert repo.get_by_id(1) is None assert repo.get_by_id(1) is None
def test_delete_nonexistent_player(self, repo, cache): def test_delete_nonexistent_player(self, repo, cache):
"""Delete fails for non-existent player.""" """Delete fails for non-existent player."""
config = ServiceConfig(player_repo=repo, cache=cache) config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config) service = PlayerService(config=config)
with patch.object(service, 'require_auth', return_value=True): with patch.object(service, "require_auth", return_value=True):
with pytest.raises(Exception) as exc_info: with pytest.raises(Exception) as exc_info:
service.delete_player(99999, 'valid_token') service.delete_player(99999, "valid_token")
assert 'not found' in str(exc_info.value) assert "not found" in str(exc_info.value)
def test_delete_requires_auth(self, repo, cache): def test_delete_requires_auth(self, repo, cache):
"""Deleting requires authentication.""" """Deleting requires authentication."""
config = ServiceConfig(player_repo=repo, cache=cache) config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config) service = PlayerService(config=config)
with pytest.raises(Exception) as exc_info: with pytest.raises(Exception) as exc_info:
service.delete_player(1, 'bad_token') service.delete_player(1, "bad_token")
assert exc_info.value.status_code == 401 assert exc_info.value.status_code == 401
class TestPlayerServiceCache:
"""Tests for cache functionality."""
@pytest.mark.skip(reason="Caching not yet implemented in service methods")
def test_cache_set_on_read(self, service, cache):
"""Cache is set on player read."""
service.get_players(season=10)
assert cache.was_called('set')
@pytest.mark.skip(reason="Caching not yet implemented in service methods")
def test_cache_invalidation_on_update(self, repo, cache):
"""Cache is invalidated on player update."""
config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config)
# Read to set cache
service.get_players(season=10)
initial_calls = len(cache.get_calls('set'))
# Update should invalidate cache
with patch.object(service, 'require_auth', return_value=True):
service.patch_player(1, {'name': 'Test'}, 'valid_token')
# Should have more delete calls after update
delete_calls = [c for c in cache.get_calls() if c.get('method') == 'delete']
assert len(delete_calls) > 0
@pytest.mark.skip(reason="Caching not yet implemented in service methods")
def test_cache_hit_rate(self, repo, cache):
"""Test cache hit rate tracking."""
config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config)
# First call - cache miss
service.get_players(season=10)
miss_count = cache._miss_count
# Second call - cache hit
service.get_players(season=10)
# Hit rate should have improved
assert cache.hit_rate > 0
class TestPlayerServiceValidation: class TestPlayerServiceValidation:
"""Tests for input validation and edge cases.""" """Tests for input validation and edge cases."""
def test_invalid_season_returns_empty(self, service): def test_invalid_season_returns_empty(self, service):
"""Invalid season returns empty result.""" """Invalid season returns empty result."""
result = service.get_players(season=999) result = service.get_players(season=999)
assert result['count'] == 0 or result['players'] == [] assert result["count"] == 0 or result["players"] == []
def test_empty_search_returns_all(self, service): def test_empty_search_returns_all(self, service):
"""Empty search query returns all players.""" """Empty search query returns all players."""
result = service.search_players('', season=10) result = service.search_players("", season=10)
assert result['count'] >= 1 assert result["count"] >= 1
def test_sort_with_no_results(self, service): def test_sort_with_no_results(self, service):
"""Sorting with no results doesn't error.""" """Sorting with no results doesn't error."""
result = service.get_players(season=999, sort='cost-desc') result = service.get_players(season=999, sort="cost-desc")
assert result['count'] == 0 or result['players'] == [] assert result["count"] == 0 or result["players"] == []
def test_cache_clear_on_create(self, repo, cache): def test_cache_clear_on_create(self, repo, cache):
"""Cache is cleared when new players are created.""" """Cache is cleared when new players are created."""
config = ServiceConfig(player_repo=repo, cache=cache) config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config) service = PlayerService(config=config)
# Set up some cache data # Set up some cache data
cache.set('test:key', 'value', 300) cache.set("test:key", "value", 300)
with patch.object(service, 'require_auth', return_value=True): with patch.object(service, "require_auth", return_value=True):
service.create_players([{ service.create_players(
'name': 'New', [
'wara': 1.0, {
'team_id': 1, "name": "New",
'season': 10, "wara": 1.0,
'pos_1': 'P' "team_id": 1,
}], 'valid_token') "season": 10,
"pos_1": "P",
}
],
"valid_token",
)
# Should have invalidate calls # Should have invalidate calls
assert len(cache.get_calls()) > 0 assert len(cache.get_calls()) > 0
class TestPlayerServiceIntegration: class TestPlayerServiceIntegration:
"""Integration tests combining multiple operations.""" """Integration tests combining multiple operations."""
def test_full_crud_cycle(self, repo, cache): def test_full_crud_cycle(self, repo, cache):
"""Test complete CRUD cycle.""" """Test complete CRUD cycle."""
config = ServiceConfig(player_repo=repo, cache=cache) config = ServiceConfig(player_repo=repo, cache=cache)
service = PlayerService(config=config) service = PlayerService(config=config)
# CREATE # CREATE
with patch.object(service, 'require_auth', return_value=True): with patch.object(service, "require_auth", return_value=True):
create_result = service.create_players([{ create_result = service.create_players(
'name': 'CRUD Test', [
'wara': 3.0, {
'team_id': 1, "name": "CRUD Test",
'season': 10, "wara": 3.0,
'pos_1': 'DH' "team_id": 1,
}], 'valid_token') "season": 10,
"pos_1": "DH",
}
],
"valid_token",
)
# READ # READ
search_result = service.search_players('CRUD', season=10) search_result = service.search_players("CRUD", season=10)
assert search_result['count'] >= 1 assert search_result["count"] >= 1
player_id = search_result['players'][0].get('id') player_id = search_result["players"][0].get("id")
# UPDATE # UPDATE
with patch.object(service, 'require_auth', return_value=True): with patch.object(service, "require_auth", return_value=True):
update_result = service.patch_player(player_id, {'wara': 4.0}, 'valid_token') update_result = service.patch_player(
assert update_result.get('wara') == 4.0 player_id, {"wara": 4.0}, "valid_token"
)
assert update_result.get("wara") == 4.0
# DELETE # DELETE
with patch.object(service, 'require_auth', return_value=True): with patch.object(service, "require_auth", return_value=True):
delete_result = service.delete_player(player_id, 'valid_token') delete_result = service.delete_player(player_id, "valid_token")
assert 'deleted' in str(delete_result) assert "deleted" in str(delete_result)
# VERIFY DELETED # VERIFY DELETED
get_result = service.get_player(player_id) get_result = service.get_player(player_id)
assert get_result is None assert get_result is None
def test_search_then_filter(self, service): def test_search_then_filter(self, service):
"""Search and then filter operations.""" """Search and then filter operations."""
# First get all players # First get all players
all_result = service.get_players(season=10) all_result = service.get_players(season=10)
initial_count = all_result['count'] initial_count = all_result["count"]
# Then filter by team # Then filter by team
filtered = service.get_players(season=10, team_id=[1]) filtered = service.get_players(season=10, team_id=[1])
# Filtered should be <= all # Filtered should be <= all
assert filtered['count'] <= initial_count assert filtered["count"] <= initial_count
# ============================================================================ # ============================================================================