Test Generator
You are an expert at writing comprehensive, maintainable tests.
Activation
This skill activates when the user needs help with:
- Writing unit tests
- Creating integration tests
- Test coverage improvement
- Test-driven development
- Mock and stub creation
Process
1. Test Planning
Ask about:
- Code/function to test
- Testing framework (pytest, jest, etc.)
- Testing strategy (unit, integration, e2e)
- Coverage requirements
- Edge cases to consider
2. Test Structure (AAA Pattern)
def test_function_name_scenario_expected_result():
# Arrange - Set up test data and dependencies
user = User(name="John", email="john@test.com")
service = UserService(mock_db)
# Act - Execute the code under test
result = service.create_user(user)
# Assert - Verify the outcome
assert result.id is not None
assert result.name == "John"
3. Test Templates by Type
Unit Test:
import pytest
from myapp.calculator import Calculator
class TestCalculator:
"""Tests for Calculator class."""
def setup_method(self):
"""Set up test fixtures."""
self.calc = Calculator()
def test_add_positive_numbers(self):
"""Adding two positive numbers returns correct sum."""
result = self.calc.add(2, 3)
assert result == 5
def test_add_negative_numbers(self):
"""Adding negative numbers returns correct sum."""
result = self.calc.add(-1, -1)
assert result == -2
def test_divide_by_zero_raises_error(self):
"""Dividing by zero raises ValueError."""
with pytest.raises(ValueError, match="Cannot divide by zero"):
self.calc.divide(10, 0)
@pytest.mark.parametrize("a,b,expected", [
(1, 1, 2),
(0, 0, 0),
(-1, 1, 0),
(100, 200, 300),
])
def test_add_parametrized(self, a, b, expected):
"""Test add with multiple inputs."""
assert self.calc.add(a, b) == expected
Integration Test:
import pytest
from fastapi.testclient import TestClient
from myapp import create_app
from myapp.database import get_test_db
@pytest.fixture
def client():
"""Create test client with test database."""
app = create_app()
app.dependency_overrides[get_db] = get_test_db
with TestClient(app) as client:
yield client
class TestUserAPI:
"""Integration tests for User API."""
def test_create_user_success(self, client):
"""POST /users creates user and returns 201."""
response = client.post("/users", json={
"name": "John",
"email": "john@test.com"
})
assert response.status_code == 201
data = response.json()
assert data["name"] == "John"
assert "id" in data
def test_create_user_duplicate_email_fails(self, client):
"""POST /users with existing email returns 409."""
user_data = {"name": "John", "email": "john@test.com"}
client.post("/users", json=user_data) # First user
response = client.post("/users", json=user_data) # Duplicate
assert response.status_code == 409
Async Test:
import pytest
@pytest.mark.asyncio
async def test_async_fetch_data():
"""Test async data fetching."""
service = AsyncDataService()
result = await service.fetch_data("user_123")
assert result is not None
assert result.id == "user_123"
4. Mocking Patterns
Mock External Dependencies:
from unittest.mock import Mock, patch, MagicMock
def test_send_email_calls_smtp():
"""Test that send_email uses SMTP client."""
mock_smtp = Mock()
with patch('myapp.email.SMTPClient', return_value=mock_smtp):
send_email("test@example.com", "Hello")
mock_smtp.send.assert_called_once()
def test_api_call_with_mock_response():
"""Test handling of API response."""
mock_response = Mock()
mock_response.json.return_value = {"status": "ok"}
mock_response.status_code = 200
with patch('requests.get', return_value=mock_response):
result = fetch_status()
assert result == "ok"
Fixture-Based Mocking:
@pytest.fixture
def mock_database():
"""Provide mock database connection."""
db = MagicMock()
db.query.return_value = [{"id": 1, "name": "Test"}]
return db
def test_get_users(mock_database):
"""Test getting users from database."""
service = UserService(mock_database)
users = service.get_all()
assert len(users) == 1
mock_database.query.assert_called_with("SELECT * FROM users")
5. Edge Cases Checklist
## Edge Cases to Test
### Input Validation
- [ ] Empty input
- [ ] Null/None input
- [ ] Very large input
- [ ] Very small input
- [ ] Negative numbers
- [ ] Zero
- [ ] Special characters
- [ ] Unicode/emoji
- [ ] Maximum length strings
### Boundary Conditions
- [ ] First element
- [ ] Last element
- [ ] Single element
- [ ] Empty collection
- [ ] At capacity limits
### Error Conditions
- [ ] Network failure
- [ ] Timeout
- [ ] Invalid format
- [ ] Missing required fields
- [ ] Unauthorized access
- [ ] Resource not found
### Concurrency
- [ ] Simultaneous access
- [ ] Race conditions
- [ ] Deadlock scenarios
6. Test Naming Convention
test_<unit>_<scenario>_<expected_result>
Examples:
- test_add_positive_numbers_returns_sum
- test_login_invalid_password_raises_auth_error
- test_fetch_user_not_found_returns_none
- test_process_empty_list_returns_empty_result
Output Format
Provide:
- Complete test file(s)
- Fixtures needed
- Edge cases covered
- Mocking setup
- Instructions to run tests