Test Writer
Overview
Generates well-structured test files for your code. Analyzes functions/classes, identifies test cases (including edge cases), and creates complete test files following best practices.
Workflow
Step 1: Analyze Code
Identify what to test:
- Function signature (parameters, types, return type)
- Behavior and dependencies
- Edge cases (None, empty, invalid input, boundaries)
- Error conditions (exceptions)
Step 2: Identify Test Cases
Systematically categorize test cases:
Test case categories:
- Happy path: Normal expected inputs
- Edge cases: Boundary values, empty collections, None
- Error cases: Invalid inputs that should raise exceptions
- Type variations: Different valid types (if applicable)
- State-dependent: Different object states (for classes)
Example for calculate_discount(price, discount_percent):
- Normal: 20% discount → 80.0
- Edge: 0% → 100.0, 100% → 0.0
- Error: negative → ValueError, >100% → ValueError
Step 3: Determine Framework
Choose testing framework (ask user if unclear):
- Python: pytest (default), unittest
- JavaScript: jest (default), mocha
- Others: Use language-appropriate framework
Step 4: Generate Test Structure
Create test file with proper structure:
File naming:
- Python:
test_[module].py in tests/ directory
- JavaScript:
[module].test.js or [module].spec.js
Use AAA pattern (Arrange-Act-Assert):
def test_calculate_discount():
# Arrange - Set up test data
price = 100.0
discount = 20.0
# Act - Call function
result = calculate_discount(price, discount)
# Assert - Verify outcome
assert result == 80.0
Step 5: Write Tests
For each test case, create test function:
- Descriptive name (
test_calculate_discount_with_normal_input)
- Docstring explaining what is tested
- Follow AAA pattern
- Use appropriate assertions
Common assertions:
- Equality:
assert result == expected
- Exceptions:
with pytest.raises(ValueError):
- Floating point:
assert result == pytest.approx(80.0)
- Collections:
assert item in result
Step 6: Add Mocks/Fixtures (if needed)
Fixtures for setup:
@pytest.fixture
def sample_data():
return {"key": "value"}
def test_with_fixture(sample_data):
assert sample_data["key"] == "value"
Mocking dependencies:
from unittest.mock import patch
def test_api_call():
with patch('module.requests.get') as mock_get:
mock_get.return_value.json.return_value = {'status': 'ok'}
result = fetch_data()
assert result['status'] == 'ok'
Parametrized tests:
@pytest.mark.parametrize("price,discount,expected", [
(100, 20, 80),
(100, 0, 100),
(50, 10, 45),
])
def test_various_inputs(price, discount, expected):
assert calculate_discount(price, discount) == expected
Step 7: Write Test File
Create complete test file with:
- Module docstring
- Imports
- Fixtures (if needed)
- Test classes/functions organized logically
- Helpful comments
Example structure:
"""Tests for calculator module."""
import pytest
from module import function_to_test
class TestFunctionName:
"""Test suite for function_to_test."""
def test_happy_path(self):
"""Test normal expected behavior."""
# Arrange
input_data = ...
# Act
result = function_to_test(input_data)
# Assert
assert result == expected
def test_edge_case(self):
"""Test with empty input."""
assert function_to_test([]) == []
def test_error_handling(self):
"""Test invalid input raises ValueError."""
with pytest.raises(ValueError):
function_to_test(invalid)
Step 8: Add Documentation
Include:
- Module docstring with test coverage summary
- Run instructions:
pytest test_module.py
- Individual test docstrings
Best Practices
Test Independence
Each test must be independent - no shared state between tests.
Descriptive Names
test_calculate_discount_raises_error_for_negative_input not test_1
Organize Tests
Group related tests in classes:
class TestUserAuthentication:
def test_login_success(self): ...
def test_login_failure(self): ...
Assertion Messages
Add helpful debug messages:
assert len(result) == 5, f"Expected 5 items, got {len(result)}"
Framework Templates
pytest (Python)
import pytest
def test_basic():
assert function(input) == expected
@pytest.mark.parametrize("input,expected", [(1, 2), (2, 4)])
def test_parametrized(input, expected):
assert function(input) == expected
def test_exception():
with pytest.raises(ValueError):
function(invalid)
jest (JavaScript)
describe('function', () => {
test('basic functionality', () => {
expect(function(input)).toBe(expected);
});
test('throws error', () => {
expect(() => function(invalid)).toThrow(Error);
});
});
Advanced Patterns
For complex scenarios, see references:
Resources
references/test_patterns.md
Comprehensive patterns for:
- Async code (asyncio, async/await)
- Database operations (fixtures, mocking)
- API endpoints (HTTP, Flask/FastAPI)
- File I/O (tmp_path, mocking)
- Time-dependent code (freezing time)
- CLI applications
- And more...
references/framework_guides.md
Quick reference for pytest, unittest, jest features and configuration.
references/mocking_guide.md
Strategies for mocking dependencies, external services, and complex scenarios.
Skill Contract
Stable: 8-step workflow, AAA pattern, test case categories, framework selection
Mutable: Framework templates, test patterns, examples
Update rules: See references/contract.md
Full contract in references/contract.md