markitect-main/tests/conftest.py

333 lines
9 KiB
Python
Raw Normal View History

feat: Implement comprehensive Testing Architecture Enhancement Establishes robust testing framework with clean architecture patterns: ## Phase 1: Test Infrastructure Foundation - Global test configuration with pytest.ini and conftest.py - Isolated test workspaces and environment management - Comprehensive fixture library for all test types - Test requirements and dependency management ## Phase 2: Advanced Testing Patterns - Test builders using builder pattern for domain objects - Mock factories for repositories, services, and configs - API response builders for external system simulation - Enhanced unit tests with proper mocking and isolation ## Phase 3: Test Performance and Quality - Performance testing framework with benchmarks - Memory usage monitoring and leak detection - Custom assertions for domain-specific validation - Parametrized testing for comprehensive coverage ## Phase 4: CI/CD Integration - GitHub Actions workflow for automated testing - Multi-stage testing: unit → integration → e2e → performance - Code quality checks with flake8, mypy, black, isort - Security scanning with safety and bandit ## Testing Architecture Benefits ✅ 100+ new test infrastructure components ✅ Standardized test organization (unit/integration/e2e) ✅ Mock-based testing with no external dependencies ✅ Performance regression detection ✅ Comprehensive fixture library ✅ CI/CD pipeline with quality gates The testing framework supports the domain logic separation and provides a solid foundation for maintaining high code quality as the system evolves. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-26 22:36:35 +02:00
"""
Global test configuration and fixtures for MarkiTect project.
Provides shared fixtures, utilities, and configuration for all test types.
"""
import pytest
import tempfile
import shutil
import asyncio
from pathlib import Path
from unittest.mock import Mock, AsyncMock
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
feat: Implement comprehensive Testing Architecture Enhancement Establishes robust testing framework with clean architecture patterns: ## Phase 1: Test Infrastructure Foundation - Global test configuration with pytest.ini and conftest.py - Isolated test workspaces and environment management - Comprehensive fixture library for all test types - Test requirements and dependency management ## Phase 2: Advanced Testing Patterns - Test builders using builder pattern for domain objects - Mock factories for repositories, services, and configs - API response builders for external system simulation - Enhanced unit tests with proper mocking and isolation ## Phase 3: Test Performance and Quality - Performance testing framework with benchmarks - Memory usage monitoring and leak detection - Custom assertions for domain-specific validation - Parametrized testing for comprehensive coverage ## Phase 4: CI/CD Integration - GitHub Actions workflow for automated testing - Multi-stage testing: unit → integration → e2e → performance - Code quality checks with flake8, mypy, black, isort - Security scanning with safety and bandit ## Testing Architecture Benefits ✅ 100+ new test infrastructure components ✅ Standardized test organization (unit/integration/e2e) ✅ Mock-based testing with no external dependencies ✅ Performance regression detection ✅ Comprehensive fixture library ✅ CI/CD pipeline with quality gates The testing framework supports the domain logic separation and provides a solid foundation for maintaining high code quality as the system evolves. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-26 22:36:35 +02:00
# 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
feat: Implement comprehensive Testing Architecture Enhancement Establishes robust testing framework with clean architecture patterns: ## Phase 1: Test Infrastructure Foundation - Global test configuration with pytest.ini and conftest.py - Isolated test workspaces and environment management - Comprehensive fixture library for all test types - Test requirements and dependency management ## Phase 2: Advanced Testing Patterns - Test builders using builder pattern for domain objects - Mock factories for repositories, services, and configs - API response builders for external system simulation - Enhanced unit tests with proper mocking and isolation ## Phase 3: Test Performance and Quality - Performance testing framework with benchmarks - Memory usage monitoring and leak detection - Custom assertions for domain-specific validation - Parametrized testing for comprehensive coverage ## Phase 4: CI/CD Integration - GitHub Actions workflow for automated testing - Multi-stage testing: unit → integration → e2e → performance - Code quality checks with flake8, mypy, black, isort - Security scanning with safety and bandit ## Testing Architecture Benefits ✅ 100+ new test infrastructure components ✅ Standardized test organization (unit/integration/e2e) ✅ Mock-based testing with no external dependencies ✅ Performance regression detection ✅ Comprehensive fixture library ✅ CI/CD pipeline with quality gates The testing framework supports the domain logic separation and provides a solid foundation for maintaining high code quality as the system evolves. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-26 22:36:35 +02:00
@pytest.fixture(scope="session")
def test_workspace() -> Generator[Path, None, None]:
"""Create isolated test workspace for file operations."""
temp_dir = tempfile.mkdtemp(prefix="markitect_test_")
workspace_path = Path(temp_dir)
# Create subdirectories
(workspace_path / "documents").mkdir()
(workspace_path / "cache").mkdir()
(workspace_path / "workspaces").mkdir()
yield workspace_path
# Cleanup
shutil.rmtree(temp_dir, ignore_errors=True)
@pytest.fixture
def test_database_path(test_workspace) -> Path:
"""Provide path for test database."""
return test_workspace / "test.db"
@pytest.fixture
def mock_database():
"""Provide mocked database for testing."""
mock_db = Mock()
mock_cursor = Mock()
mock_db.cursor.return_value = mock_cursor
mock_db.execute.return_value = mock_cursor
mock_cursor.fetchone.return_value = None
mock_cursor.fetchall.return_value = []
mock_cursor.lastrowid = 1
return mock_db
@pytest.fixture
def mock_http_client():
"""Provide mocked HTTP client for API tests."""
mock_client = Mock()
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"status": "success"}
mock_response.text = '{"status": "success"}'
mock_client.get.return_value = mock_response
mock_client.post.return_value = mock_response
mock_client.put.return_value = mock_response
mock_client.delete.return_value = mock_response
return mock_client
@pytest.fixture
def mock_async_http_client():
"""Provide mocked async HTTP client for API tests."""
mock_client = AsyncMock()
mock_response = AsyncMock()
mock_response.status = 200
mock_response.json = AsyncMock(return_value={"status": "success"})
mock_response.text = AsyncMock(return_value='{"status": "success"}')
mock_client.get.return_value = mock_response
mock_client.post.return_value = mock_response
mock_client.put.return_value = mock_response
mock_client.delete.return_value = mock_response
return mock_client
@pytest.fixture
def test_config(test_workspace) -> Dict[str, Any]:
"""Provide test configuration dictionary."""
return {
"workspace_dir": str(test_workspace / "workspaces"),
"database_path": str(test_workspace / "test.db"),
"cache_dir": str(test_workspace / "cache"),
"gitea_url": "http://test-gitea.com",
"gitea_token": "test-token",
"repo_owner": "test",
"repo_name": "repo",
"log_level": "DEBUG"
}
@pytest.fixture
def clean_environment():
"""Provide clean environment variables for testing."""
original_env = dict(os.environ)
# Clear relevant environment variables
test_env_vars = [
"MARKITECT_WORKSPACE_DIR",
"MARKITECT_GITEA_URL",
"MARKITECT_GITEA_TOKEN",
"MARKITECT_REPO_OWNER",
"MARKITECT_REPO_NAME"
]
for var in test_env_vars:
os.environ.pop(var, None)
yield
# Restore original environment
os.environ.clear()
os.environ.update(original_env)
@pytest.fixture
def isolated_environment(test_workspace, clean_environment):
"""Set up isolated environment for CLI testing."""
env = {
"MARKITECT_WORKSPACE_DIR": str(test_workspace / "workspaces"),
"MARKITECT_GITEA_URL": "http://test-gitea.com",
"MARKITECT_GITEA_TOKEN": "test-token",
"MARKITECT_REPO_OWNER": "test",
"MARKITECT_REPO_NAME": "repo",
"PYTHONPATH": "."
}
# Update current process environment
for key, value in env.items():
os.environ[key] = value
yield env
@pytest.fixture
def sample_markdown_content():
"""Provide sample markdown content for testing."""
return """---
title: Test Document
author: Test Author
tags: [test, sample]
---
# Test Document
This is a test document with **bold** and *italic* text.
## Section 1
- Item 1
- Item 2
- Item 3
## Section 2
Here's a code block:
```python
def hello_world():
print("Hello, World!")
```
And a link: [Test Link](https://example.com)
"""
@pytest.fixture
def sample_issue_data():
"""Provide sample issue data for testing."""
return {
"number": 123,
"title": "Test Issue",
"body": "This is a test issue description",
"state": "open",
"labels": [
{"name": "bug"},
{"name": "priority:high"},
{"name": "status:in-progress"}
],
"milestone": {
"id": 1,
"title": "Version 1.0",
"description": "First release"
},
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T12:00:00Z"
}
@pytest.fixture
def sample_project_data():
"""Provide sample project data for testing."""
return {
"name": "Test Project",
"description": "A test project for testing",
"state": "active",
"milestones": [
{
"id": 1,
"title": "Version 1.0",
"description": "First release",
"due_date": "2025-12-31T23:59:59Z",
"state": "open",
"open_issues": 5,
"closed_issues": 3
}
],
"kanban_columns": ["Todo", "In Progress", "Review", "Done"],
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
# Performance testing fixtures
@pytest.fixture
def performance_timer():
"""Timer fixture for performance testing."""
import time
class Timer:
def __init__(self):
self.start_time = None
self.end_time = None
def start(self):
self.start_time = time.time()
def stop(self):
self.end_time = time.time()
@property
def elapsed(self) -> float:
if self.start_time is None:
raise ValueError("Timer not started")
if self.end_time is None:
return time.time() - self.start_time
return self.end_time - self.start_time
return Timer()
# Async test helpers
@pytest.fixture
def async_test_timeout():
"""Default timeout for async tests."""
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
feat: Implement comprehensive Testing Architecture Enhancement Establishes robust testing framework with clean architecture patterns: ## Phase 1: Test Infrastructure Foundation - Global test configuration with pytest.ini and conftest.py - Isolated test workspaces and environment management - Comprehensive fixture library for all test types - Test requirements and dependency management ## Phase 2: Advanced Testing Patterns - Test builders using builder pattern for domain objects - Mock factories for repositories, services, and configs - API response builders for external system simulation - Enhanced unit tests with proper mocking and isolation ## Phase 3: Test Performance and Quality - Performance testing framework with benchmarks - Memory usage monitoring and leak detection - Custom assertions for domain-specific validation - Parametrized testing for comprehensive coverage ## Phase 4: CI/CD Integration - GitHub Actions workflow for automated testing - Multi-stage testing: unit → integration → e2e → performance - Code quality checks with flake8, mypy, black, isort - Security scanning with safety and bandit ## Testing Architecture Benefits ✅ 100+ new test infrastructure components ✅ Standardized test organization (unit/integration/e2e) ✅ Mock-based testing with no external dependencies ✅ Performance regression detection ✅ Comprehensive fixture library ✅ CI/CD pipeline with quality gates The testing framework supports the domain logic separation and provides a solid foundation for maintaining high code quality as the system evolves. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-26 22:36:35 +02:00
# Test markers configuration
def pytest_configure(config):
"""Configure pytest markers."""
config.addinivalue_line(
"markers", "slow: marks tests as slow (deselect with '-m \"not slow\"')"
)
config.addinivalue_line(
"markers", "integration: marks tests as integration tests"
)
config.addinivalue_line(
"markers", "e2e: marks tests as end-to-end tests"
)
config.addinivalue_line(
"markers", "performance: marks tests as performance tests"
)
config.addinivalue_line(
"markers", "unit: marks tests as unit tests"
)
# Collection hooks
def pytest_collection_modifyitems(config, items):
"""Modify test collection to add markers based on test location."""
for item in items:
# Add markers based on test file location
if "unit" in str(item.fspath):
item.add_marker(pytest.mark.unit)
elif "integration" in str(item.fspath):
item.add_marker(pytest.mark.integration)
elif "e2e" in str(item.fspath):
item.add_marker(pytest.mark.e2e)
elif "performance" in str(item.fspath):
item.add_marker(pytest.mark.performance)