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].pyintests/directory - •JavaScript:
[module].test.jsor[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:
- •Async/database/API testing: See test_patterns.md
- •Framework-specific features: See framework_guides.md
- •Mocking strategies: See mocking_guide.md
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