Intelligent Python unit test generation with Socratic planning and project-specific memory.
Resources
3Install
npx skillscat add olino3/forge/generate-python-unit-tests Install via the SkillsCat registry.
Step 1: Initial Analysis
Purpose: Gather information about what needs to be tested.
Actions:
- Identify the Python file(s) or module(s) to test
- Determine the project name from git repository or directory structure
- Check if tests already exist for the target files
- Identify the testing framework (pytest, unittest, etc.)
- List the functions/classes/methods that need test coverage
Validation:
- Target files identified
- Project name determined
- Testing framework detected
- Functions/classes to test listed
Step 2: Load Index Files
Purpose: Understand what memory and context is available.
Actions:
- Load Python domain index via
contextProvider.getDomainIndex("python") - Identify which context topics will be needed based on code analysis
Validation:
- Domain index loaded
- Python context map understood
- Relevant topics identified
Step 3: Load Project Memory
Purpose: Load project-specific testing patterns and conventions.
Actions:
- Load project memory via
memoryStore.getSkillMemory("generate-python-unit-tests", project) - If memory exists, review all files:
testing_patterns.md- Project's testing conventionsexpected_behaviors.md- Known expected behaviorscommon_fixtures.md- Reusable test fixturesframework_config.md- Testing framework setup
- If no memory exists, note that this is a new project (memory will be created later)
Validation:
- Project memory checked
- Existing patterns loaded (if available)
- Ready to create new memory (if needed)
Step 4: Load Context
Purpose: Load testing standards and best practices.
Actions:
Always load:
contextProvider.getConditionalContext("python", "unit_testing_standards")contextProvider.getConditionalContext("python", "testing_frameworks")contextProvider.getConditionalContext("python", "mocking_patterns")contextProvider.getConditionalContext("python", "test_antipatterns")
Conditionally load (based on code analysis):
- If async code: load async patterns via contextProvider
- If Django/Flask/FastAPI: load framework-specific context
- If database code: load data testing patterns
- Use domain index from Step 2 as guide
Validation:
- Core testing context loaded
- Framework-specific context loaded (if needed)
- Ready to apply testing standards
Step 5: Analyze Files to Test
Purpose: Understand the code structure and dependencies.
Actions:
- Read the target Python file(s) completely
- Identify:
- Public functions/methods (primary test targets)
- Function signatures and parameters
- Dependencies (imports, external services)
- Error handling (exceptions raised)
- Complexity and edge cases
- Read existing tests (if any) to understand coverage gaps
- Analyze project structure to determine test file location
Validation:
- Target code thoroughly understood
- Dependencies identified
- Edge cases noted
- Test file location determined
Step 6: Socratic Planning Phase
Purpose: Collaborate with the user to understand expected behavior.
CRITICAL: This step is MANDATORY. You MUST ask the user questions before generating tests.
Actions:
- Present a summary of what you analyzed
- Ask targeted questions using the Socratic Questions Framework:
- Behavior questions: Expected outputs, edge cases, errors
- Dependency questions: What to mock, external services
- Business logic questions: Rules, constraints, validations
- Testing approach questions: Style preferences, test types
- Wait for user responses
- Use AskUserQuestion tool for structured multi-choice questions when appropriate
- Clarify ambiguities and confirm understanding
Example Questions:
I analyzed `user_service.py` and found 3 functions to test:
- create_user(username, email, password)
- authenticate_user(username, password)
- delete_user(user_id)
Before generating tests, I need to understand the expected behavior:
1. **For create_user**:
- What should happen if username already exists?
- Should it validate email format?
- What password requirements should I test?
2. **For authenticate_user**:
- Should I mock the database lookup?
- What happens with invalid credentials?
- Are there rate limiting or security concerns?
3. **For delete_user**:
- What happens if user doesn't exist?
- Should it handle cascade deletions?
- Are there permission checks to test?
4. **General**:
- Do you prefer pytest or unittest?
- Should I use fixtures for common setup?Validation:
- Summary presented to user
- At least 3-5 meaningful questions asked
- User responses received
- Expected behaviors clarified
- Testing approach confirmed
Step 7: Generate Unit Tests
Purpose: Create comprehensive, maintainable unit tests.
Actions:
- Create test file following project conventions:
- File naming:
test_{module_name}.pyor{module_name}_test.py - Location: Based on project structure (e.g.,
tests/,test/, same directory)
- File naming:
- Apply templates from
./templates/test_file_template.txt - For each function/method:
- Generate happy path tests
- Generate edge case tests
- Generate error scenario tests
- Use AAA pattern (Arrange, Act, Assert)
- Include:
- Descriptive test names (test_should_X_when_Y)
- Appropriate mocks/patches
- Fixtures for common setup
- Docstrings for complex tests
- Apply project memory patterns and user's clarified behaviors
- Follow framework-specific conventions (pytest vs unittest)
Validation:
- Test file created in correct location
- All functions have test coverage
- Happy paths tested
- Edge cases tested
- Error scenarios tested
- Project conventions followed
- User's expected behaviors implemented
Step 8: Update Project Memory
Purpose: Store learned patterns for future test generation.
Actions:
- Use
memoryStore.update("generate-python-unit-tests", project, filename, content)for each file - Create or update memory files:
- testing_patterns.md: Document testing conventions observed/established
- Test file location pattern
- Naming conventions
- Testing framework and version
- Common patterns used
- expected_behaviors.md: Document clarified behaviors from Socratic phase
- Function behaviors confirmed with user
- Edge case handling rules
- Error scenarios and expected exceptions
- common_fixtures.md: Document reusable test fixtures created
- Shared setup code
- Common mock objects
- Test data factories
- framework_config.md: Document testing framework configuration
- pytest.ini / setup.cfg settings
- Conftest.py patterns
- Plugin usage
- testing_patterns.md: Document testing conventions observed/established
Validation:
- Project memory directory exists
- testing_patterns.md created/updated
- expected_behaviors.md created/updated
- common_fixtures.md created/updated
- framework_config.md created/updated
Purpose
Intelligent Python unit test generation with Socratic planning and project-specific memory.
Compliance Checklist
Before completing the skill invocation, verify ALL items:
Workflow Compliance
- Step 1: Initial Analysis completed
- Step 2: Index files loaded
- Step 3: Project memory loaded
- Step 4: Context loaded
- Step 5: Files analyzed
- Step 6: Socratic planning completed (questions asked and answered)
- Step 7: Tests generated
- Step 8: Memory updated
Test Quality
- Tests follow AAA pattern
- Test names are descriptive
- Appropriate mocking used
- Edge cases covered
- Error scenarios covered
- Tests are independent
- Project conventions followed
Memory & Context
- Project memory checked and loaded
- New patterns documented in memory
- User-clarified behaviors stored
- Testing context applied
User Collaboration
- Socratic questions asked (minimum 3-5)
- User responses incorporated
- Expected behaviors confirmed
Best Practices
Test Organization
File Structure:
- Mirror source code structure in tests
- One test file per source file (generally)
- Group related tests in classes
Test Naming:
test_should_{expected_behavior}_when_{condition}- Be specific and descriptive
- Use underscores for readability
Test Independence:
- Each test should run independently
- Use fixtures for setup/teardown
- Avoid test interdependencies
Mocking Strategy
What to Mock:
- External services (APIs, databases)
- File system operations
- Time/date operations
- Random number generation
- Expensive computations
What NOT to Mock:
- Code under test
- Simple data structures
- Language built-ins (unless necessary)
Coverage Strategy
Priority Order:
- Happy path (normal operation)
- Common edge cases
- Error scenarios
- Boundary conditions
- Integration points
Sufficiency:
- Aim for meaningful coverage, not 100%
- Focus on critical business logic
- Test public interfaces
Additional Notes
Testing Frameworks
pytest (preferred):
- Use fixtures for setup
- Parametrize tests for multiple cases
- Use markers for categorization
- Leverage pytest plugins
unittest:
- Use setUp/tearDown for fixtures
- Subclass unittest.TestCase
- Use self.assert* methods
- Mock with unittest.mock
Integration with Other Skills
- Before testing: Use
skill:python-code-reviewto understand code quality - After testing: Review generated tests with
skill:python-code-review - For changes: Use
skill:get-git-diffto see what changed and needs new tests
Common Patterns
- Fixtures:
@pytest.fixture
def sample_user():
return User(username="test", email="test@example.com")- Parameterization:
@pytest.mark.parametrize("input,expected", [
(1, 2),
(2, 4),
(3, 6),
])
def test_double(input, expected):
assert double(input) == expected- Mocking:
@patch('module.external_api_call')
def test_function(mock_api):
mock_api.return_value = {'status': 'success'}
result = function_using_api()
assert result == expectedMemory Evolution
Project memory should grow with each invocation:
- First time: Establish basic patterns
- Subsequent times: Refine and expand patterns
- Always: Store user-clarified behaviors
Context Usage
Context files provide stable guidance:
- Testing standards (what makes a good test)
- Framework patterns (how to use pytest/unittest)
- Antipatterns (what to avoid)
- Mocking strategies (when and how to mock)
Version History
v1.1.0 (2025-07-15)
- Phase 4 Migration: Replaced hardcoded
../../context/and../../memory/paths with ContextProvider and MemoryStore interface calls - Added YAML frontmatter with context/memory declarations
- Added Interface References section
- Updated workflow steps to use contextProvider/memoryStore
v1.0.0 (2025-11-18)
- Initial release
- Mandatory 8-step workflow
Step 1: Initial Analysis
Gather inputs and determine scope and requirements.
Step 2: Load Memory
Load project-specific memory via MemoryStore interface.
Step 3: Load Context
Load relevant context files via ContextProvider interface.
Step 4: Core Implementation
Execute the skill-specific core action.
Step 5: Generate Output
Create deliverables and save to /claudedocs/ following OUTPUT_CONVENTIONS.md.
Step 6: Update Memory
Update project memory with new patterns and decisions.