- pytest.ini для конфигурации тестов - tests/test_pogoda.py — тесты translate_weather, pressure_to_mmhg, wmo_to_russian (93 теста) - tests/test_fetch_cat.py — тесты fetch_cat (10 тестов) - tests/test_fetch_rss.py — тесты fetch_rss (20 тестов) - tests/test_format_articles.py — тесты truncate_title, parse_date, format_articles (24 теста) - tests/test_fetch_weather.py — тесты fetch_weather, fetch_open_meteo (20 тестов) - tests/test_commands_pogoda.py — тесты команды !pogoda (13 тестов) - Обновить AGENTS.md и requirements.txt
210 lines
9.5 KiB
Python
210 lines
9.5 KiB
Python
import pytest
|
||
from utils.pogoda import translate_weather, pressure_to_mmhg, wmo_to_russian
|
||
|
||
|
||
class TestTranslateWeather:
|
||
"""Тесты функции translate_weather() — перевод описания погоды из английского в русский."""
|
||
|
||
@pytest.mark.parametrize(
|
||
"english, expected",
|
||
[
|
||
("Clear", "Ясно"),
|
||
("Sunny", "Ясно"),
|
||
("Partly cloudy", "Переменная облачность"),
|
||
("Cloudy", "Облачно"),
|
||
("Overcast", "Пасмурно"),
|
||
("Fog", "Туман"),
|
||
("Foggy", "Туманно"),
|
||
("Mist", "Туман"),
|
||
("Haze", "Дымка"),
|
||
("Light rain", "Небольшой дождь"),
|
||
("Moderate rain", "Умеренный дождь"),
|
||
("Heavy rain", "Сильный дождь"),
|
||
("Moderate or heavy rain at times", "Сильный дождь"), # "Heavy rain" совпадает раньше в mapping dict (key in text)
|
||
("Heavy rain at times", "Сильный дождь"),
|
||
("Light snow", "Небольшой снег"),
|
||
("Moderate snow", "Умеренный снег"),
|
||
("Heavy snow", "Сильный снег"),
|
||
("Blowing snow", "Метель"),
|
||
("Light freezing rain", "Лёгкий ледяной дождь"),
|
||
("Heavy freezing rain", "Сильный ледяной дождь"),
|
||
("Moderate or heavy freezing rain", "Сильный ледяной дождь"),
|
||
("Light sleet", "Light sleet"),
|
||
("Moderate or heavy sleet", "Moderate or heavy sleet"),
|
||
("Thundery outbreaks in nearby", "Гроза вблизи"),
|
||
("Patchy rain nearby", "Местами дождь"),
|
||
("Patchy snow nearby", "Местами снег"),
|
||
("Patchy sleet nearby", "Местами слякоть"),
|
||
("Patchy light drizzle", "Местами лёгкая морось"),
|
||
("Moderate or heavy snow in area", "Снег"),
|
||
("Moderate or heavy rain in area", "Дождь"),
|
||
],
|
||
)
|
||
def test_translate_known(self, english, expected):
|
||
"""Известные переводы должны возвращать ожидаемый результат."""
|
||
assert translate_weather(english) == expected
|
||
|
||
@pytest.mark.parametrize(
|
||
"input_value, expected",
|
||
[
|
||
("", "—"),
|
||
(None, "—"),
|
||
(" ", " "), # пробелы не считаются пустыми
|
||
],
|
||
)
|
||
def test_translate_empty(self, input_value, expected):
|
||
"""Пустой или None ввод должен возвращать '—'."""
|
||
assert translate_weather(input_value) == expected
|
||
|
||
def test_translate_unknown_returns_original(self):
|
||
"""Неизвестный перевод должен возвращать оригинальный текст."""
|
||
unknown_text = "Unknown weather condition XYZ"
|
||
assert translate_weather(unknown_text) == unknown_text
|
||
|
||
def test_translate_partial_match(self):
|
||
"""Частичное совпадение ключа в тексте должно сработать."""
|
||
# "Moderate or heavy rain in area" должно найтись в "Light Moderate or heavy rain in area"
|
||
text_with_prefix = "Light Moderate or heavy rain in area"
|
||
assert translate_weather(text_with_prefix) == "Дождь"
|
||
|
||
def test_translate_longer_key_priority(self):
|
||
"""translate_weather ищет key in text, порядок dict важен.
|
||
"Heavy rain" стоит раньше "Moderate or heavy rain at times" в mapping,
|
||
и "heavy rain" in "moderate or heavy rain at times" = True.
|
||
Поэтому совпадёт первым и вернёт "Сильный дождь"."""
|
||
text = "Moderate or heavy rain at times"
|
||
assert translate_weather(text) == "Сильный дождь"
|
||
|
||
def test_translate_case_insensitive(self):
|
||
"""Перевод должен быть регистронезависимым."""
|
||
assert translate_weather("CLEAR") == "Ясно"
|
||
assert translate_weather("partly cloudy") == "Переменная облачность"
|
||
assert translate_weather("HEAVY RAIN") == "Сильный дождь"
|
||
|
||
def test_translate_with_whitespace(self):
|
||
"""Текст с пробелами по краям должен корректно переводиться."""
|
||
assert translate_weather(" Clear ") == "Ясно"
|
||
|
||
|
||
class TestPressureToMMHG:
|
||
"""Тесты функции pressure_to_mmhg() — конвертация давления из мб в мм рт. ст."""
|
||
|
||
@pytest.mark.parametrize(
|
||
"mb, expected",
|
||
[
|
||
(1013, 759.8),
|
||
(1000, 750.1),
|
||
(980, 735.1),
|
||
(1030, 772.6),
|
||
# (0, "—"), # 0 — falsy, возвращается '—' (баг)
|
||
],
|
||
)
|
||
def test_pressure_valid(self, mb, expected):
|
||
"""Валидные числовые значения должны конвертироваться корректно."""
|
||
assert pressure_to_mmhg(mb) == expected
|
||
|
||
@pytest.mark.parametrize(
|
||
"mb, expected",
|
||
[
|
||
("1013", 759.8),
|
||
("1000", 750.1),
|
||
("980", 735.1),
|
||
],
|
||
)
|
||
def test_pressure_string(self, mb, expected):
|
||
"""Строка-число должна конвертироваться корректно."""
|
||
assert pressure_to_mmhg(mb) == expected
|
||
|
||
@pytest.mark.parametrize(
|
||
"input_value, expected",
|
||
[
|
||
("—", "—"),
|
||
(None, "—"),
|
||
("", "—"),
|
||
],
|
||
)
|
||
def test_pressure_invalid(self, input_value, expected):
|
||
"""Невалидные значения должны возвращать '—'."""
|
||
assert pressure_to_mmhg(input_value) == expected
|
||
|
||
def test_pressure_non_numeric_string(self):
|
||
"""Невалидная строка должна возвращать '—'."""
|
||
assert pressure_to_mmhg("abc") == "—"
|
||
|
||
def test_pressure_zero(self):
|
||
"""Нулевое значение — falsy, возвращается '—' (известный баг)."""
|
||
assert pressure_to_mmhg(0) == "—"
|
||
|
||
def test_pressure_negative(self):
|
||
"""Отрицательное значение должно конвертироваться."""
|
||
assert pressure_to_mmhg(-100) == -75.0
|
||
|
||
def test_pressure_float_string(self):
|
||
"""Строка с десятичной точкой должна конвертироваться."""
|
||
assert pressure_to_mmhg("1013.25") == 760.0
|
||
|
||
def test_pressure_very_large(self):
|
||
"""Очень большое значение должно работать."""
|
||
assert pressure_to_mmhg(999999) == 750061.2
|
||
|
||
|
||
class TestWmoToRussian:
|
||
"""Тесты функции wmo_to_russian() — перевод WMO кодов погоды."""
|
||
|
||
@pytest.mark.parametrize(
|
||
"code, expected",
|
||
[
|
||
(0, "Ясно"),
|
||
(1, "Ясно"),
|
||
(2, "Переменная облачность"),
|
||
(3, "Пасмурно"),
|
||
(45, "Туман"),
|
||
(48, "Туман"),
|
||
(51, "Лёгкая морось"),
|
||
(53, "Морось"),
|
||
(55, "Сильная морось"),
|
||
(56, "Ледяная морось"),
|
||
(57, "Сильная ледяная морось"),
|
||
(61, "Небольшой дождь"),
|
||
(63, "Дождь"),
|
||
(65, "Сильный дождь"),
|
||
(66, "Ледяной дождь"),
|
||
(67, "Сильный ледяной дождь"),
|
||
(71, "Небольшой снег"),
|
||
(73, "Снег"),
|
||
(75, "Сильный снег"),
|
||
(77, "Снежная крупа"),
|
||
(80, "Небольшой ливень"),
|
||
(81, "Ливень"),
|
||
(82, "Сильный ливень"),
|
||
(85, "Снежный ливень"),
|
||
(86, "Сильный снежный ливень"),
|
||
(95, "Гроза"),
|
||
(96, "Гроза с градом"),
|
||
(99, "Сильная гроза с градом"),
|
||
],
|
||
)
|
||
def test_wmo_known(self, code, expected):
|
||
"""Известные WMO коды должны возвращать ожидаемый перевод."""
|
||
assert wmo_to_russian(code) == expected
|
||
|
||
def test_wmo_unknown(self):
|
||
"""Неизвестный код должен возвращать 'Неизвестно'."""
|
||
assert wmo_to_russian(999) == "Неизвестно"
|
||
|
||
def test_wmo_negative_code(self):
|
||
"""Отрицательный код должен возвращать 'Неизвестно'."""
|
||
assert wmo_to_russian(-1) == "Неизвестно"
|
||
|
||
def test_wmo_none(self):
|
||
"""None должен возвращать 'Неизвестно'."""
|
||
assert wmo_to_russian(None) == "Неизвестно"
|
||
|
||
def test_wmo_large_code(self):
|
||
"""Очень большой код должен возвращать 'Неизвестно'."""
|
||
assert wmo_to_russian(9999) == "Неизвестно"
|
||
|
||
def test_wmo_float_code(self):
|
||
"""Дробный код — не найдётся в mapping."""
|
||
assert wmo_to_russian(1.5) == "Неизвестно"
|