mirror of
https://github.com/lintsinghua/DeepAudit.git
synced 2026-10-25 18:11:29 +08:00
6.6 KiB
6.6 KiB
Testing Guide
This document describes the testing strategy and how to run tests for XCodeReviewer.
Test Structure
tests/
├── test_api_endpoints.py # API endpoint tests
├── test_e2e_workflows.py # End-to-end workflow tests
├── test_llm_service.py # LLM service tests
├── test_repository_scanner.py # Repository scanning tests
├── test_report_generation.py # Report generation tests
└── conftest.py # Shared fixtures
Test Categories
Unit Tests
Test individual components in isolation.
pytest tests/ -m unit
Integration Tests
Test interactions between components.
pytest tests/ -m integration
End-to-End Tests
Test complete user workflows.
pytest tests/ -m e2e
Running Tests
Run All Tests
# Using pytest directly
pytest
# Using test script
./scripts/run_tests.sh
Run Specific Test File
pytest tests/test_api_endpoints.py
Run Specific Test Class
pytest tests/test_api_endpoints.py::TestAuthEndpoints
Run Specific Test
pytest tests/test_api_endpoints.py::TestAuthEndpoints::test_register_user
Run with Coverage
pytest --cov=. --cov-report=html
Run in Parallel
pytest -n auto
Coverage Reports
Generate Coverage Report
pytest --cov=. --cov-report=html --cov-report=term
View HTML Report
open htmlcov/index.html # macOS
xdg-open htmlcov/index.html # Linux
start htmlcov/index.html # Windows
Coverage Threshold
The project requires minimum 80% code coverage. Tests will fail if coverage is below this threshold.
Test Fixtures
Common fixtures are defined in conftest.py:
db_session: Database session for teststest_client: HTTP client for API testsauthenticated_user: Pre-authenticated test userauth_token: Authentication token
Writing Tests
Unit Test Example
def test_password_validation():
"""Test password validation logic"""
from core.security import validate_password
# Valid password
assert validate_password("SecurePass123!")
# Invalid password
assert not validate_password("weak")
Integration Test Example
@pytest.mark.asyncio
async def test_create_project(test_client, auth_token):
"""Test project creation via API"""
response = await test_client.post(
"/api/v1/projects",
headers={"Authorization": f"Bearer {auth_token}"},
json={
"name": "Test Project",
"source_type": "github"
}
)
assert response.status_code == 201
E2E Test Example
@pytest.mark.e2e
@pytest.mark.asyncio
async def test_complete_workflow(test_client, auth_token):
"""Test complete analysis workflow"""
# Create project
project = await create_project(test_client, auth_token)
# Create task
task = await create_task(test_client, auth_token, project["id"])
# Generate report
report = await generate_report(test_client, auth_token, task["id"])
assert report["status"] == "completed"
Mocking
Mock External Services
from unittest.mock import patch, MagicMock
@patch('services.llm.openai_adapter.OpenAI')
def test_llm_call(mock_openai):
"""Test LLM service with mocked API"""
mock_openai.return_value.chat.completions.create.return_value = MagicMock(
choices=[MagicMock(message=MagicMock(content="Test response"))]
)
# Test code here
Mock Database
@pytest.fixture
async def mock_db():
"""Mock database session"""
from unittest.mock import AsyncMock
session = AsyncMock()
session.commit = AsyncMock()
session.rollback = AsyncMock()
return session
Continuous Integration
Tests run automatically on:
- Pull requests
- Commits to main branch
- Scheduled daily runs
GitHub Actions Workflow
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run tests
run: ./scripts/run_tests.sh
- name: Upload coverage
uses: codecov/codecov-action@v2
Performance Testing
Load Testing with Locust
from locust import HttpUser, task, between
class APIUser(HttpUser):
wait_time = between(1, 3)
@task
def list_projects(self):
self.client.get("/api/v1/projects")
Run load test:
locust -f tests/load_test.py --host=http://localhost:8000
Security Testing
SQL Injection Tests
def test_sql_injection_protection(test_client, auth_token):
"""Test SQL injection protection"""
response = test_client.get(
"/api/v1/projects",
params={"search": "'; DROP TABLE projects; --"}
)
assert response.status_code != 500
Authentication Tests
def test_unauthorized_access(test_client):
"""Test unauthorized access is blocked"""
response = test_client.get("/api/v1/projects")
assert response.status_code == 401
Debugging Tests
Run with Debug Output
pytest -vv --tb=long
Run with PDB
pytest --pdb
Run Specific Failed Tests
pytest --lf # Last failed
pytest --ff # Failed first
Best Practices
- Test Naming: Use descriptive names that explain what is being tested
- Arrange-Act-Assert: Structure tests clearly
- One Assertion: Focus each test on one behavior
- Independent Tests: Tests should not depend on each other
- Fast Tests: Keep unit tests fast (< 1 second)
- Mock External Services: Don't make real API calls in tests
- Clean Up: Use fixtures to clean up test data
- Coverage: Aim for 80%+ coverage
- Documentation: Add docstrings to test functions
- Markers: Use pytest markers to categorize tests
Troubleshooting
Tests Hanging
# Add timeout
pytest --timeout=30
Database Conflicts
# Use separate test database
export TEST_DATABASE_URL=sqlite+aiosqlite:///./test.db
Import Errors
# Add project root to PYTHONPATH
export PYTHONPATH="${PYTHONPATH}:$(pwd)"
Async Tests Failing
# Ensure pytest-asyncio is installed
pip install pytest-asyncio