fix: обновить тесты distance_service под канон B5 (3e2692f)

Тесты проверяли старые бэкендовские скорости (1.0–5.5 км/ч), тогда как
B5 перенёс в живую копию services/distance_service.py каноничные
displacement-скорости фронта (0.3–2.5 км/ч, априоры ПСО «Экстремум»,
94% в 3 км) и сумерки 0.7.

Обновлены ожидания (пересчитаны все кейсы):
- TestBaseSpeed: 0.3/0.7/1.2/1.5/2.0/2.5/2.5/1.5 по возрастам
- 5 кейсов calculate_max_distance пересчитаны (5.12→1.92 и т.д.)
- test_twilight: 0.5 → 0.7
- test_statistics_values: base_speed 4.0 → 1.5
- test_fatigue_minimum: 27.0 → 13.5
- Добавлена контрольная точка B5: bike 8yo 2h лес = 5.4 км

Коэффициенты в services/ НЕ тронуты (B1-safe) — только тесты.

201 passed, 0 failed.
This commit is contained in:
2026-09-09 10:56:28 +03:00
parent 3e38aae2be
commit 1119793145
+69 -56
View File
@@ -18,12 +18,18 @@ from services.distance_service import (
class TestCalculateMaxDistance:
"""Test the main distance calculation function."""
"""Test the main distance calculation function.
Ожидания соответствуют каноничным displacement-скоростям B5 (3e2692f):
get_base_speed 0.3–2.5 км/ч по априорам ПСО «Экстремум» (94% в 3 км).
Контрольная точка B5: bike 8yo 2h лес = 5.4 км.
"""
def test_boy_10_years_4_hours_forest_rain(self):
"""
Test case from requirements:
Мальчик 10 лет, 4 часа, лес, дождь → ~5 км
Мальчик 10 лет, 4 часа, лес, дождь.
Пересчитано под канон B5: НормС(10)=1.5
Distance = 4 * 1.5 * 0.5 * 0.8 * 1.0 * 0.8 = 1.92 km
"""
case_data = {
'age': 10,
@@ -32,20 +38,10 @@ class TestCalculateMaxDistance:
'time_of_day': 'день',
'weather': 'дождь'
}
distance = calculate_max_distance(case_data)
# Expected calculation:
# Time = 4 hours
# НормС (age 10) = 4.0 km/h
# СП (лес) = 0.5
# СУТ (4 hours) = 1.0 - (0.05 * 4) = 0.8
# ВВС (день) = 1.0
# ВП (дождь) = 0.8
# Distance = 4 * 4.0 * 0.5 * 0.8 * 1.0 * 0.8 = 5.12 km
assert 4.5 <= distance <= 5.5, f"Expected ~5 km, got {distance} km"
assert distance == pytest.approx(5.12, rel=0.01)
assert distance == pytest.approx(1.92, rel=0.01)
def test_young_child_short_time(self):
"""Test for young child (3 years) with short elapsed time."""
@@ -56,11 +52,11 @@ class TestCalculateMaxDistance:
'time_of_day': 'день',
'weather': 'нет'
}
distance = calculate_max_distance(case_data)
# Expected: 1 * 2.0 * 0.5 * 0.95 * 1.0 * 1.0 = 0.95 km
assert distance == pytest.approx(0.95, rel=0.01)
# 1 * 0.7 * 0.5 * 0.95 * 1.0 * 1.0 = 0.33 km
assert distance == pytest.approx(0.33, rel=0.01)
def test_teenager_long_time_road(self):
"""Test for teenager on road with longer elapsed time."""
@@ -71,11 +67,11 @@ class TestCalculateMaxDistance:
'time_of_day': 'день',
'weather': 'нет'
}
distance = calculate_max_distance(case_data)
# Expected: 6 * 5.0 * 0.8 * 0.7 * 1.0 * 1.0 = 16.8 km
assert distance == pytest.approx(16.8, rel=0.01)
# 6 * 2.0 * 0.8 * 0.7 * 1.0 * 1.0 = 6.72 km
assert distance == pytest.approx(6.72, rel=0.01)
def test_elderly_night_swamp(self):
"""Test for elderly person at night in swamp."""
@@ -86,11 +82,11 @@ class TestCalculateMaxDistance:
'time_of_day': 'ночь',
'weather': 'туман'
}
distance = calculate_max_distance(case_data)
# Expected: 3 * 3.0 * 0.2 * 0.85 * 0.5 * 0.7 = 0.54 km
assert distance == pytest.approx(0.54, rel=0.01)
# 3 * 1.5 * 0.2 * 0.85 * 0.5 * 0.7 = 0.27 km
assert distance == pytest.approx(0.27, rel=0.01)
def test_adult_heavy_rain_field(self):
"""Test for adult in heavy rain on field."""
@@ -101,46 +97,62 @@ class TestCalculateMaxDistance:
'time_of_day': 'день',
'weather': 'ливень'
}
distance = calculate_max_distance(case_data)
# Expected: 2 * 5.0 * 0.9 * 0.9 * 1.0 * 0.6 = 4.86 km
assert distance == pytest.approx(4.86, rel=0.01)
# 2 * 2.5 * 0.9 * 0.9 * 1.0 * 0.6 = 2.43 km
assert distance == pytest.approx(2.43, rel=0.01)
def test_bike_8yo_canonical_b5(self):
"""Контрольная точка B5: bike 8yo 2h лес = 5.4 км (СУ bike ×5)."""
case_data = {
'age': 8,
'elapsed_hours': 2.0,
'terrain_primary': 'лес',
'time_of_day': 'день',
'weather': 'нет',
'has_transport': 'bike',
'diagnosis_type': [],
}
distance = calculate_max_distance(case_data)
assert distance == pytest.approx(5.4, rel=0.01)
class TestBaseSpeed:
"""Test НормС (base speed) by age."""
"""Test НормС (base speed) by age — каноничные displacement-скорости B5."""
def test_infant(self):
assert get_base_speed(1) == 1.0
assert get_base_speed(2) == 1.0
assert get_base_speed(1) == 0.3
assert get_base_speed(2) == 0.3
def test_preschool(self):
assert get_base_speed(3) == 2.0
assert get_base_speed(5) == 2.0
assert get_base_speed(3) == 0.7
assert get_base_speed(5) == 0.7
def test_young_child(self):
assert get_base_speed(6) == 3.0
assert get_base_speed(8) == 3.0
assert get_base_speed(6) == 1.2
assert get_base_speed(8) == 1.2
def test_preteen(self):
assert get_base_speed(10) == 4.0
assert get_base_speed(12) == 4.0
assert get_base_speed(10) == 1.5
assert get_base_speed(12) == 1.5
def test_teenager(self):
assert get_base_speed(13) == 5.0
assert get_base_speed(15) == 5.0
assert get_base_speed(16) == 5.5
assert get_base_speed(17) == 5.5
assert get_base_speed(13) == 2.0
assert get_base_speed(15) == 2.0
assert get_base_speed(16) == 2.5
assert get_base_speed(17) == 2.5
def test_adult(self):
assert get_base_speed(25) == 5.0
assert get_base_speed(50) == 5.0
assert get_base_speed(64) == 5.0
assert get_base_speed(25) == 2.5
assert get_base_speed(50) == 2.5
assert get_base_speed(64) == 2.5
def test_elderly(self):
assert get_base_speed(65) == 3.0
assert get_base_speed(80) == 3.0
assert get_base_speed(65) == 1.5
assert get_base_speed(80) == 1.5
class TestTerrainCoefficient:
@@ -184,8 +196,9 @@ class TestTimeOfDayCoefficient:
assert get_time_of_day_coefficient('ночь') == 0.5
def test_twilight(self):
assert get_time_of_day_coefficient('сумерки') == 0.5
assert get_time_of_day_coefficient('вечер') == 0.5
# B5: сумерки/вечер = 0.7 (было 0.5 — канон фронта)
assert get_time_of_day_coefficient('сумерки') == 0.7
assert get_time_of_day_coefficient('вечер') == 0.7
class TestWeatherCoefficient:
@@ -294,7 +307,7 @@ class TestDistanceStatistics:
terrain='лес'
)
assert stats['base_speed_kmh'] == 4.0
assert stats['base_speed_kmh'] == 1.5
assert stats['terrain_coefficient'] == 0.5
assert stats['max_distance_km'] > 0
assert 0 <= stats['zone_probability'] <= 1.0
@@ -336,6 +349,6 @@ class TestFatigueCoefficient:
}
distance = calculate_max_distance(case_data)
# 20 * 5.0 * 0.9 * 0.3 * 1.0 * 1.0 = 27.0
assert distance == pytest.approx(27.0, rel=0.01)
# 20 * 2.5 * 0.9 * 0.3 * 1.0 * 1.0 = 13.5
assert distance == pytest.approx(13.5, rel=0.01)