test: add comprehensive test suite - Closes #7

Added comprehensive test coverage for all tool modules:

Test Files Created:
- tests/conftest.py: Shared fixtures for all tests
- tests/test_issues.py: Complete coverage for issue tools
- tests/test_labels.py: Complete coverage for label tools
- tests/test_milestones.py: Complete coverage for milestone tools

Test Coverage:
- Tool definition validation (schema structure)
- Handler function routing
- Successful API response formatting
- Error handling (GiteaClientError)
- Required parameter validation
- Optional parameter handling
- Mock Gitea API responses

Configuration Updates:
- Added pytest-cov>=4.0.0 to dev dependencies
- Created run_tests.sh script for easy test execution

All tests use pytest-asyncio for async functions and mock the
GiteaClient to avoid real API calls. Tests validate tool schemas,
handler routing, response formatting, and error handling.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-03 15:30:09 -05:00
parent ab8c9069da
commit 2230bceb51
6 changed files with 1087 additions and 0 deletions

103
tests/conftest.py Normal file
View File

@@ -0,0 +1,103 @@
"""Shared pytest fixtures for Gitea MCP tests."""
import pytest
from unittest.mock import AsyncMock, MagicMock
from gitea_mcp.auth import AuthConfig
from gitea_mcp.client import GiteaClient
@pytest.fixture
def mock_config(monkeypatch):
"""Create mock authentication config.
This fixture sets up test environment variables and returns
a configured AuthConfig instance for testing.
"""
monkeypatch.setenv("GITEA_API_URL", "http://gitea.example.com/api/v1")
monkeypatch.setenv("GITEA_API_TOKEN", "test_token_123")
return AuthConfig()
@pytest.fixture
def mock_client(mock_config):
"""Create a mock GiteaClient instance.
Returns a GiteaClient with mocked HTTP methods that don't make
real API calls. Use this for testing tool handlers.
"""
client = GiteaClient(mock_config, timeout=10.0)
# Mock the internal HTTP client methods
client.get = AsyncMock()
client.post = AsyncMock()
client.patch = AsyncMock()
client.delete = AsyncMock()
# Mock context manager
client.__aenter__ = AsyncMock(return_value=client)
client.__aexit__ = AsyncMock(return_value=None)
return client
@pytest.fixture
def sample_issue():
"""Sample issue data for testing.
Returns a dict representing a typical Gitea issue response.
"""
return {
"id": 1,
"number": 42,
"title": "Test Issue",
"body": "This is a test issue",
"state": "open",
"created_at": "2024-01-15T10:00:00Z",
"updated_at": "2024-01-15T12:00:00Z",
"html_url": "http://gitea.example.com/test/repo/issues/42",
"labels": [
{"id": 1, "name": "bug", "color": "ff0000"},
{"id": 2, "name": "priority-high", "color": "ff9900"},
],
"milestone": {
"id": 10,
"title": "v1.0",
"state": "open",
},
"assignees": [
{"id": 100, "login": "testuser"},
],
}
@pytest.fixture
def sample_label():
"""Sample label data for testing.
Returns a dict representing a typical Gitea label response.
"""
return {
"id": 1,
"name": "bug",
"color": "ff0000",
"description": "Something isn't working",
}
@pytest.fixture
def sample_milestone():
"""Sample milestone data for testing.
Returns a dict representing a typical Gitea milestone response.
"""
return {
"id": 10,
"title": "v1.0",
"description": "First major release",
"state": "open",
"open_issues": 5,
"closed_issues": 15,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-15T12:00:00Z",
"due_on": "2024-12-31T23:59:59Z",
}