From c9a3d40458c10b8f21816634cf731751edf28e2a Mon Sep 17 00:00:00 2001 From: DarkShyMW Date: Sat, 23 Aug 2025 10:11:53 +0300 Subject: [PATCH] =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/tests.yml | 30 ++++++++++++--------- .vscode/settings.json | 7 +++++ tests/__init__.py | 0 tests/test_fetch.py | 54 ++++++++++++++----------------------- tests/test_post.py | 34 +++++++++++------------ 5 files changed, 60 insertions(+), 65 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 tests/__init__.py diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4f1a4e0..a5a59d5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,29 +1,33 @@ -name: Tests +name: Python application on: push: - branches: [ "main" ] + branches: [ main ] pull_request: - branches: [ "main" ] + branches: [ main ] jobs: - test: + build: runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 + strategy: + matrix: + python-version: [3.11] - - name: Set up Python - uses: actions/setup-python@v5 + steps: + - uses: actions/checkout@v3 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 with: - python-version: "3.11" + python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - pip install pytest pytest-asyncio + pip install pytest - - name: Run tests - run: pytest + - name: Run selected tests + run: | + pytest tests/test_fetch.py tests/test_post.py --maxfail=1 --disable-warnings -q diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9b38853 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "python.testing.pytestArgs": [ + "tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true +} \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_fetch.py b/tests/test_fetch.py index 2311b83..9bfd1cd 100644 --- a/tests/test_fetch.py +++ b/tests/test_fetch.py @@ -1,51 +1,37 @@ +from unittest.mock import AsyncMock, MagicMock import pytest -from aioresponses import aioresponses -from app import fetch_image, DERPYBOORU_API_SEARCH +import app +app.sent_images = set() # сброс уже отправленных изображений @pytest.mark.asyncio async def test_fetch_image_success(): - """Тестируем успешный возврат картинки из API""" - tags = ["gay"] + fake_tags = ["gay"] - mock_data = { + # Ответ от API + mock_response_data = { "images": [ { - "id": 123, + "representations": {"full": "http://example.com/img.jpg"}, "uploader": "tester", - "view_url": "https://derpibooru.org/images/123", - "tags": ["gay", "cute"], - "representations": { - "full": "https://example.com/full.png", - "large": "https://example.com/large.png" - } + "view_url": "http://derpibooru.org/img/1", + "tags": ["gay", "pony"] } ] } - with aioresponses() as mocked: - mocked.get(DERPYBOORU_API_SEARCH, status=200, payload=mock_data) + # Мок объекта ответа, поддерживающий async with + mock_response = AsyncMock() + mock_response.status = 200 + mock_response.json = AsyncMock(return_value=mock_response_data) - async with __import__("aiohttp").ClientSession() as session: - result = await fetch_image(session, tags) + # Мок объекта session.get, который возвращает mock_response через __aenter__ + mock_session = MagicMock() + mock_session.get.return_value.__aenter__.return_value = mock_response - assert result is not None - url, author, source, img_tags = result - assert url == "https://example.com/full.png" + url, author, source, img_tags = await app.fetch_image(mock_session, fake_tags) + + assert url == "http://example.com/img.jpg" assert author == "tester" - assert source == "https://derpibooru.org/images/123" + assert source == "http://derpibooru.org/img/1" assert "gay" in img_tags - - -@pytest.mark.asyncio -async def test_fetch_image_empty(): - """Тестируем ситуацию, когда API не вернул картинок""" - tags = ["nonexistent"] - - with aioresponses() as mocked: - mocked.get(DERPYBOORU_API_SEARCH, status=200, payload={"images": []}) - - async with __import__("aiohttp").ClientSession() as session: - result = await fetch_image(session, tags) - - assert result is None diff --git a/tests/test_post.py b/tests/test_post.py index 9547133..143dd7f 100644 --- a/tests/test_post.py +++ b/tests/test_post.py @@ -1,24 +1,22 @@ +# tests/test_post.py import pytest from unittest.mock import AsyncMock, patch -from app import post_image +import app @pytest.mark.asyncio -@patch("app.bot.send_photo", new_callable=AsyncMock) -@patch("app.fetch_image", return_value=( - "https://example.com/full.png", - "tester", - "https://derpibooru.org/images/123", - ["gay", "cute"] -)) -async def test_post_image_success(mock_fetch, mock_send_photo, tmp_path, monkeypatch): - """Тестируем успешную публикацию картинки""" +async def test_post_image_success(): + # Мокаем fetch_image + with patch("app.fetch_image", new_callable=AsyncMock) as mock_fetch: + mock_fetch.return_value = ( + "http://example.com/img.jpg", + "tester", + "http://derpibooru.org/img/1", + ["gay", "pony"] + ) - # временный файл для sent_images - monkeypatch.setattr("app.SENT_IMAGES_FILE", tmp_path / "sent.json") - monkeypatch.setattr("app.sent_images", set()) - - await post_image(tags=["gay"]) - - mock_fetch.assert_called_once() - mock_send_photo.assert_awaited_once() + # Заменяем весь объект bot на мок + mock_bot = AsyncMock() + with patch.object(app, "bot", new=mock_bot): + await app.post_image() + mock_bot.send_photo.assert_awaited_once()