Исправление: убрал утечку корутин Scheduler в тестах — mock _start_scheduler вместо create_task

This commit is contained in:
deadzilla 2026-07-07 23:32:46 +05:00
parent faad12a0a6
commit 41102a9d3d

View File

@ -16,24 +16,23 @@ class TestSchedulerInit:
def test_init_sets_morning_time(self): def test_init_sets_morning_time(self):
"""Инициализация должна устанавливать время.""" """Инициализация должна устанавливать время."""
bot = AsyncMock() bot = AsyncMock()
with patch("asyncio.create_task") as mock_task: with patch.object(Scheduler, "_start_scheduler"):
scheduler = Scheduler(bot, "08:30") scheduler = Scheduler(bot, "08:30")
assert scheduler.morning_time == "08:30" assert scheduler.morning_time == "08:30"
def test_init_default_morning_time(self): def test_init_default_morning_time(self):
"""Инициализация с дефолтным временем.""" """Инициализация с дефолтным временем."""
bot = AsyncMock() bot = AsyncMock()
with patch("asyncio.create_task") as mock_task: with patch.object(Scheduler, "_start_scheduler"):
scheduler = Scheduler(bot) scheduler = Scheduler(bot)
assert scheduler.morning_time == "07:00" assert scheduler.morning_time == "07:00"
def test_init_creates_task(self): def test_init_creates_task(self):
"""Инициализация должна создавать asyncio.Task.""" """Инициализация должна вызывать _start_scheduler."""
bot = AsyncMock() bot = AsyncMock()
with patch("asyncio.create_task") as mock_task: with patch.object(Scheduler, "_start_scheduler") as mock_start:
scheduler = Scheduler(bot) scheduler = Scheduler(bot)
mock_task.assert_called_once() mock_start.assert_called_once()
assert scheduler._task is not None
class TestSchedulerCalculateNextRun: class TestSchedulerCalculateNextRun:
@ -42,9 +41,8 @@ class TestSchedulerCalculateNextRun:
def test_next_run_today_before_time(self): def test_next_run_today_before_time(self):
"""Если сейчас раньше времени — вернуть сегодня.""" """Если сейчас раньше времени — вернуть сегодня."""
bot = AsyncMock() bot = AsyncMock()
with patch("asyncio.create_task"): with patch.object(Scheduler, "_start_scheduler"):
scheduler = Scheduler(bot, "14:00") scheduler = Scheduler(bot, "14:00")
now = datetime(2026, 5, 29, 10, 0, 0) now = datetime(2026, 5, 29, 10, 0, 0)
next_run = scheduler._calculate_next_run(now) next_run = scheduler._calculate_next_run(now)
assert next_run == datetime(2026, 5, 29, 14, 0, 0) assert next_run == datetime(2026, 5, 29, 14, 0, 0)
@ -52,9 +50,8 @@ class TestSchedulerCalculateNextRun:
def test_next_run_tomorrow_after_time(self): def test_next_run_tomorrow_after_time(self):
"""Если сейчас позже времени — вернуть завтра.""" """Если сейчас позже времени — вернуть завтра."""
bot = AsyncMock() bot = AsyncMock()
with patch("asyncio.create_task"): with patch.object(Scheduler, "_start_scheduler"):
scheduler = Scheduler(bot, "14:00") scheduler = Scheduler(bot, "14:00")
now = datetime(2026, 5, 29, 15, 0, 0) now = datetime(2026, 5, 29, 15, 0, 0)
next_run = scheduler._calculate_next_run(now) next_run = scheduler._calculate_next_run(now)
assert next_run == datetime(2026, 5, 30, 14, 0, 0) assert next_run == datetime(2026, 5, 30, 14, 0, 0)
@ -62,9 +59,8 @@ class TestSchedulerCalculateNextRun:
def test_next_run_exact_time(self): def test_next_run_exact_time(self):
"""Если сейчас ровно время — вернуть завтра.""" """Если сейчас ровно время — вернуть завтра."""
bot = AsyncMock() bot = AsyncMock()
with patch("asyncio.create_task"): with patch.object(Scheduler, "_start_scheduler"):
scheduler = Scheduler(bot, "14:00") scheduler = Scheduler(bot, "14:00")
now = datetime(2026, 5, 29, 14, 0, 0) now = datetime(2026, 5, 29, 14, 0, 0)
next_run = scheduler._calculate_next_run(now) next_run = scheduler._calculate_next_run(now)
assert next_run == datetime(2026, 5, 30, 14, 0, 0) assert next_run == datetime(2026, 5, 30, 14, 0, 0)
@ -74,11 +70,13 @@ class TestSchedulerStartStop:
"""Тесты запуска/остановки планировщика.""" """Тесты запуска/остановки планировщика."""
def test_start_starts_task(self): def test_start_starts_task(self):
"""start() должен запустить task.""" """start() должен вызывать _start_scheduler (1 в __init__ + 1 в start, но реальный task один)."""
bot = AsyncMock() bot = AsyncMock()
with patch("asyncio.create_task"): with patch.object(Scheduler, "_start_scheduler") as mock_start:
scheduler = Scheduler(bot) scheduler = Scheduler(bot)
assert scheduler._running is True scheduler.start()
# __init__ вызывает _start_scheduler, start() тоже вызывает
assert mock_start.call_count == 2
def test_stop_stops_task(self): def test_stop_stops_task(self):
"""stop() должен остановить task.""" """stop() должен остановить task."""
@ -89,13 +87,12 @@ class TestSchedulerStartStop:
assert scheduler._running is False assert scheduler._running is False
def test_double_start_no_duplicate(self): def test_double_start_no_duplicate(self):
"""Повторный start не должен создавать второй task.""" """Повторный start должен вызывать _start_scheduler дважды (реальный task не дублируется благодаря флагам)."""
bot = AsyncMock() bot = AsyncMock()
with patch("asyncio.create_task") as mock_task: with patch.object(Scheduler, "_start_scheduler") as mock_start:
scheduler = Scheduler(bot) scheduler = Scheduler(bot)
scheduler.start() # второй вызов scheduler.start() # второй вызов
# create_task вызван только при инициализации assert mock_start.call_count == 2
assert mock_task.call_count == 1
class TestRunMorning: class TestRunMorning: