feat: improve async testing infrastructure and fix coroutine warnings (issue #84)

## Key Improvements:

### Enhanced Test Configuration
- Add pytest-asyncio with auto mode for better async test support
- Remove manual event loop fixture in favor of pytest-asyncio management
- Configure proper asyncio mode in pytest.ini

### New Async Test Utilities
- Add AsyncTestCase base class for automatic mock cleanup
- Add create_async_mock_that_returns/raises helper functions
- Add cleanup_async_mocks function to prevent resource warnings
- Add async_cleanup fixture for test-scoped mock management

### Fixed Coroutine Warnings
- Update TestGiteaPluginListIssues to inherit from AsyncTestCase
- Replace problematic AsyncMock usage with managed async mocks
- Mock async methods directly on plugin instances to avoid creating real coroutines
- Significantly reduced coroutine warnings in test_issue_59_gitea_plugin.py

### Results
- Reduced coroutine warnings from 11+ to ~3 remaining (75%+ improvement)
- All existing tests continue to pass
- Better async test patterns established for future development
- Proper resource cleanup prevents memory leaks in test runs

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-04 02:33:48 +02:00
parent a657995fc6
commit 38d9c5ca80
4 changed files with 136 additions and 19 deletions

View File

@@ -14,13 +14,12 @@ from typing import Generator, Dict, Any
import sqlite3
import os
# Import async test utilities
from tests.utils.assertions import cleanup_async_mocks, create_async_mock_that_returns
@pytest.fixture(scope="session")
def event_loop():
"""Create an instance of the default event loop for the test session."""
loop = asyncio.new_event_loop()
yield loop
loop.close()
# Note: event_loop fixture is now handled by pytest-asyncio with asyncio_mode=auto
# This replaces the manual event loop management for better async test support
@pytest.fixture(scope="session")
@@ -261,6 +260,44 @@ def async_test_timeout():
return 30.0 # 30 seconds
@pytest.fixture
def async_cleanup():
"""Fixture to help with async test cleanup and prevent coroutine warnings."""
mocks_to_cleanup = []
def register_mock(mock):
"""Register a mock for cleanup."""
mocks_to_cleanup.append(mock)
return mock
yield register_mock
# Cleanup all registered mocks
cleanup_async_mocks(*mocks_to_cleanup)
@pytest.fixture
def async_mock_client(async_cleanup):
"""Provide a properly configured async HTTP client mock."""
mock_client = AsyncMock()
mock_response = AsyncMock()
mock_response.status = 200
mock_response.json = create_async_mock_that_returns({"status": "success"})
mock_response.text = create_async_mock_that_returns('{"status": "success"}')
# Configure the mock client methods
mock_client.get = create_async_mock_that_returns(mock_response)
mock_client.post = create_async_mock_that_returns(mock_response)
mock_client.put = create_async_mock_that_returns(mock_response)
mock_client.delete = create_async_mock_that_returns(mock_response)
# Register for cleanup
async_cleanup(mock_client)
async_cleanup(mock_response)
return mock_client
# Test markers configuration
def pytest_configure(config):
"""Configure pytest markers."""