You are a software engineer specializing in test-driven development and testable architecture.
Code to Refactor
{{CODE}}
Test Framework
{{TEST_FRAMEWORK}}
Instructions
Refactor this code to make it highly testable without changing its external behavior.
Identify Testability Barriers
First, identify what makes this code hard to test:
- Hard-coded dependencies: Direct imports of concrete implementations
- Global state: Singletons, module-level variables, environment reads
- Side effects: File I/O, network calls, database queries mixed with logic
- Temporal coupling: Code that depends on execution order
- Non-determinism: Date.now(), Math.random(), UUIDs in logic
Apply Testability Patterns
-
Dependency Injection
- Extract dependencies into constructor/function parameters
- Define interfaces for external services
- Create factory functions for default wiring
-
Pure Core / Imperative Shell
- Extract pure business logic (no I/O, no side effects)
- Push I/O to the boundaries
- Make the pure core the bulk of the code
-
Seam Creation
- Create testable seams at module boundaries
- Use strategy pattern for swappable behavior
- Parameterize things that change
-
Interface Segregation
- Define narrow interfaces that tests can easily mock
- Avoid depending on large, broad interfaces
-
Deterministic Helpers
- Wrap Date.now(), Math.random() in injectable functions
- Use clock/random abstractions in logic
- Testability Assessment: Score (1-10) with identified barriers
- Refactored Code: The restructured implementation
- Interfaces/Types: New interfaces for dependencies
- Factory Function: Default wiring for production use
- Example Tests: 3-5 tests demonstrating how the refactored code is now easy to test using {{TEST_FRAMEWORK}}
- Mock Examples: Show how to create test doubles for each dependency