import requests from requests.exceptions import ConnectionError, Timeout, SSLError from unittest.mock import patch, MagicMock from utils.cat import fetch_cat class TestFetchCat: """Тесты функции fetch_cat() — получение URL случайного котика.""" @patch("utils.cat._session.get") async def test_fetch_cat_success(self, mock_get) -> None: """Успешный ответ с URL должен вернуть строку.""" mock_response = MagicMock() mock_response.json.return_value = [{"url": "https://example.com/cat.jpg"}] mock_response.raise_for_status = MagicMock() mock_get.return_value = mock_response result = await fetch_cat() assert result == "https://example.com/cat.jpg" @patch("utils.cat._session.get") async def test_fetch_cat_empty_array(self, mock_get) -> None: """Пустой массив должен вернуть None.""" mock_response = MagicMock() mock_response.json.return_value = [] mock_response.raise_for_status = MagicMock() mock_get.return_value = mock_response result = await fetch_cat() assert result is None @patch("utils.cat._session.get") async def test_fetch_cat_http_error(self, mock_get) -> None: """HTTP-ошибка (raise_for_status) должна вернуть None.""" mock_response = MagicMock() mock_response.raise_for_status.side_effect = requests.HTTPError("404 Not Found") mock_get.return_value = mock_response result = await fetch_cat() assert result is None @patch("utils.cat._session.get") async def test_fetch_cat_connection_error(self, mock_get) -> None: """ConnectionError должна вернуть None.""" mock_get.side_effect = ConnectionError("No connection") result = await fetch_cat() assert result is None @patch("utils.cat._session.get") async def test_fetch_cat_timeout(self, mock_get) -> None: """Timeout должна вернуть None.""" mock_get.side_effect = Timeout("Request timed out") result = await fetch_cat() assert result is None @patch("utils.cat._session.get") async def test_fetch_cat_ssl_error(self, mock_get) -> None: """SSLError должна вернуть None.""" mock_get.side_effect = SSLError("SSL handshake failed") result = await fetch_cat() assert result is None @patch("utils.cat._session.get") async def test_fetch_cat_json_parse_error(self, mock_get) -> None: """Ошибка парсинга JSON должна вернуть None.""" mock_response = MagicMock() mock_response.json.side_effect = requests.JSONDecodeError( "Expecting value", "", 0 ) mock_response.raise_for_status = MagicMock() mock_get.return_value = mock_response result = await fetch_cat() assert result is None @patch("utils.cat._session.get") async def test_fetch_cat_missing_url_key(self, mock_get) -> None: """Отсутствие ключа 'url' в ответе должно вернуть None.""" mock_response = MagicMock() mock_response.json.return_value = [{"error": "no image"}] mock_response.raise_for_status = MagicMock() mock_get.return_value = mock_response result = await fetch_cat() assert result is None @patch("utils.cat._session.get") async def test_fetch_cat_request_exception(self, mock_get) -> None: """Общий RequestException должен вернуть None.""" mock_get.side_effect = requests.RequestException("Generic error") result = await fetch_cat() assert result is None @patch("utils.cat._session.get") async def test_fetch_cat_url_with_special_chars(self, mock_get) -> None: """URL со спецсимволами должен вернуться как есть.""" mock_response = MagicMock() mock_response.json.return_value = [ {"url": "https://example.com/cat?w=100&h=200"} ] mock_response.raise_for_status = MagicMock() mock_get.return_value = mock_response result = await fetch_cat() assert result == "https://example.com/cat?w=100&h=200"