Spaces:
Sleeping
Sleeping
File size: 4,865 Bytes
6424951 92a832f 6424951 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | """Tests for ML model module."""
from unittest.mock import MagicMock, patch
import numpy as np
import pytest
from src.ml.model import ModelLoadError, analyze_team_stats, predict_winner
class TestAnalyzeTeamStats:
"""Tests for analyze_team_stats function."""
def test_flattens_stats_correctly(
self, sample_team_stats: list[list[float]]
) -> None:
"""Test that team stats are flattened correctly."""
home_array, away_array, combined = analyze_team_stats(
sample_team_stats, sample_team_stats
)
# Each team has 5 players x 10 stats = 50 values
assert home_array.shape == (1, 50)
assert away_array.shape == (1, 50)
# Combined has both teams = 100 values
assert combined.shape == (1, 100)
def test_combined_contains_both_teams(
self, sample_team_stats: list[list[float]]
) -> None:
"""Test that combined array contains both teams' stats."""
home_stats = [[1.0, 2.0], [3.0, 4.0]] # 2 players, 2 stats each
away_stats = [[5.0, 6.0], [7.0, 8.0]]
_home_array, _away_array, combined = analyze_team_stats(
home_stats, away_stats
)
# Home should be first 4 values, away next 4
np.testing.assert_array_equal(
combined[0], [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
)
class TestPredictWinner:
"""Tests for predict_winner function."""
@patch("src.ml.model.get_winner_model")
def test_returns_probability_and_prediction(
self, mock_get_model: MagicMock
) -> None:
"""Test that function returns (probability, prediction) tuple."""
mock_model = MagicMock()
mock_model.predict.return_value = np.array([[0.75]])
mock_get_model.return_value = mock_model
stats = np.random.rand(1, 100)
probability, prediction = predict_winner(stats)
assert isinstance(probability, float)
assert isinstance(prediction, int)
assert 0.0 <= probability <= 1.0
assert prediction in (0, 1)
@patch("src.ml.model.get_winner_model")
def test_high_probability_predicts_win(
self, mock_get_model: MagicMock
) -> None:
"""Test that high probability (>0.5) predicts home win (1)."""
mock_model = MagicMock()
mock_model.predict.return_value = np.array([[0.8]])
mock_get_model.return_value = mock_model
stats = np.random.rand(1, 100)
probability, prediction = predict_winner(stats)
assert probability == 0.8
assert prediction == 1
@patch("src.ml.model.get_winner_model")
def test_low_probability_predicts_loss(
self, mock_get_model: MagicMock
) -> None:
"""Test that low probability (<0.5) predicts home loss (0)."""
mock_model = MagicMock()
mock_model.predict.return_value = np.array([[0.3]])
mock_get_model.return_value = mock_model
stats = np.random.rand(1, 100)
probability, prediction = predict_winner(stats)
assert probability == 0.3
assert prediction == 0
@patch("src.ml.model.get_winner_model")
def test_invalid_shape_raises_error(
self, mock_get_model: MagicMock
) -> None:
"""Test that invalid input shape raises ValueError."""
mock_model = MagicMock()
mock_get_model.return_value = mock_model
# Wrong shape
stats = np.random.rand(1, 50)
with pytest.raises(ValueError) as exc_info:
predict_winner(stats)
assert "Expected input shape (1, 100)" in str(exc_info.value)
@patch("src.ml.model.get_winner_model")
def test_model_called_with_verbose_zero(
self, mock_get_model: MagicMock
) -> None:
"""Test that model.predict is called with verbose=0."""
mock_model = MagicMock()
mock_model.predict.return_value = np.array([[0.5]])
mock_get_model.return_value = mock_model
stats = np.random.rand(1, 100)
predict_winner(stats)
mock_model.predict.assert_called_once_with(stats, verbose=0)
class TestGetWinnerModel:
"""Tests for get_winner_model caching."""
@patch("src.ml.model.load_model")
@patch("src.ml.model.Path")
def test_raises_error_for_missing_model(
self, mock_path: MagicMock, mock_load: MagicMock
) -> None:
"""Test that missing model file raises ModelLoadError."""
from src.ml.model import get_winner_model
# Clear the cache to ensure fresh test
get_winner_model.clear()
mock_path_instance = MagicMock()
mock_path_instance.exists.return_value = False
mock_path.return_value = mock_path_instance
with pytest.raises(ModelLoadError) as exc_info:
get_winner_model("nonexistent.keras")
assert "not found" in str(exc_info.value)
|