tdd-workflow
Guide test-driven development workflow for PowerShell code in this project. Use when: (1) Implementing new features or functions, (2) Modifying existing functions, (3) Fixing bugs, (4) Refactoring code. This skill provides the Red-Green-Refactor cycle workflow and ensures tests and implementation are always committed together.
SKILL.md
| Name | tdd-workflow |
| Description | Guide test-driven development workflow for PowerShell code in this project. Use when: (1) Implementing new features or functions, (2) Modifying existing functions, (3) Fixing bugs, (4) Refactoring code. This skill provides the Red-Green-Refactor cycle workflow and ensures tests and implementation are always committed together. |
name: tdd-workflow description: Guide test-driven development workflow for PowerShell code in this project. Use when: (1) Implementing new features or functions, (2) Modifying existing functions, (3) Fixing bugs, (4) Refactoring code. This skill provides the Red-Green-Refactor cycle workflow and ensures tests and implementation are always committed together.
TDD Workflow
Step-by-step test-driven development workflow for PowerShell code following Red-Green-Refactor principles.
The Red-Green-Refactor Cycle
RED: Write a Failing Test
- Write a test that describes the desired behavior
- Run the test - it should FAIL (red)
- Verify the failure is for the right reason
GREEN: Make the Test Pass
- Write the minimum code needed to pass the test
- Run the test - it should PASS (green)
- Don't worry about code quality yet
REFACTOR: Improve the Code
- Clean up the code while keeping tests passing
- Remove duplication (DRY)
- Improve readability
- Run tests frequently during refactoring
Workflow Steps
For New Features
-
Write the test (RED phase)
Describe "New-FeatureName" { It "Should handle basic case" { $result = New-FeatureName -Input "test" $result | Should -Be "expected" } } -
Run tests - confirm failure
pwsh -File ".\test\bin\testrunner.ps1" -UnitExpected output: Test fails because function doesn't exist
-
Implement minimal code (GREEN phase)
function New-FeatureName { param([string]$Input) return "expected" } -
Run tests - confirm pass
pwsh -File ".\test\bin\testrunner.ps1" -UnitExpected output: Test passes
-
Refactor if needed (REFACTOR phase)
- Improve implementation
- Add error handling
- Remove duplication
- Keep tests passing
-
Commit test + implementation together
git add tools/pslib/utils.ps1 tools/pslib/utils.Tests.ps1 git commit -m "feat: add New-FeatureName function"
For Modifying Existing Functions
CRITICAL: Never modify implementation without updating tests!
-
Read existing tests
- Understand what behavior is currently tested
- Identify gaps in test coverage
-
Update tests for new behavior (RED phase)
It "Should handle new case" { $result = Existing-Function -NewParameter "value" $result | Should -Be "expected-new-behavior" } -
Run tests - confirm failure
pwsh -File ".\test\bin\testrunner.ps1" -UnitExpected: New test fails, existing tests pass
-
Update implementation (GREEN phase)
function Existing-Function { param( [string]$OldParameter, [string]$NewParameter # New parameter ) # Updated logic } -
Run tests - confirm all pass
pwsh -File ".\test\bin\testrunner.ps1" -UnitExpected: All tests pass
-
Commit test + implementation together
git add tools/pslib/utils.ps1 tools/pslib/utils.Tests.ps1 git commit -m "feat: add NewParameter to Existing-Function"
For Bug Fixes
-
Write test that reproduces the bug (RED phase)
It "Should handle edge case that was failing" { $result = Function-With-Bug -EdgeCase "value" $result | Should -Be "correct-behavior" } -
Run test - confirm it fails
- Test should fail, demonstrating the bug
-
Fix the bug (GREEN phase)
- Modify implementation to pass the new test
- Ensure existing tests still pass
-
Run all tests
pwsh -File ".\test\bin\testrunner.ps1" -Unit -
Commit test + fix together
git add file.ps1 file.Tests.ps1 git commit -m "fix: handle edge case in Function-With-Bug"
Quick Reference Commands
Run Unit Tests (Fast Feedback Loop)
pwsh -File ".\test\bin\testrunner.ps1" -Unit
Run Integration Tests
pwsh -File ".\test\bin\testrunner.ps1" -Integration
Run All Tests
pwsh -File ".\test\bin\testrunner.ps1"
Run Tests with Coverage
pwsh -File ".\test\bin\testrunner.ps1" -Unit -Coverage
Run Specific Test File
pwsh -File ".\test\bin\testrunner.ps1" -TestPath "tools\pslib\utils.Tests.ps1"
TDD Best Practices
- Write the smallest test possible - Test one behavior at a time
- See it fail first - Never skip the RED phase
- Write minimal code - Only enough to pass the test
- Refactor with confidence - Tests protect against regressions
- Keep tests fast - Mock external dependencies in unit tests
- Test behavior, not implementation - Focus on what, not how
- One assertion per test - Each test verifies one thing
- Commit tests and implementation together - They are inseparable
Common Mistakes to Avoid
- Skipping the RED phase - Writing tests after implementation
- Committing implementation without tests - Tests must be in same commit
- Committing tests without implementation - Implementation must be in same commit
- Not running tests before committing - All tests must pass
- Testing implementation details - Test public interface, not internals
- Writing too much code - Implement only what's needed to pass tests
- Ignoring failing tests - All tests must pass before proceeding
Example Workflow
See tdd-examples.md for complete step-by-step examples from the codebase.
Integration with pester-exec Skill
For detailed testing execution guidance, use the pester-exec skill:
- Running tests on different PowerShell versions
- CI/CD integration patterns
- Troubleshooting test failures
- Advanced Pester features