Testable code design patterns for TypeScript/React applications. Triggers: テスタビリティ, testability, テスト可能, テストしやすい, モック, mock, 純粋関数, pure function, 依存性注入, dependency injection, DI, 副作用, side effect, 副作用分離, テスト困難, hard to test.
/plugin marketplace add thkt/claude-config/plugin install complete-workflow-system@thkt-development-workflowsThis skill is limited to using the following tools:
references/dependency-injection.mdreferences/mock-friendly.mdreferences/pure-functions.mdTarget: Code that is easy to test without complex mocking or setup.
| Indicator | Good | Warning |
|---|---|---|
| Mock complexity | Simple stubs | Deep mock chains |
| Test setup | < 10 lines | > 30 lines |
| Dependencies | Explicit (params/props) | Hidden (imports) |
| Side effects | Isolated | Mixed with logic |
| State | Predictable | Global/mutable |
| Section | File | Focus | Triggers |
|---|---|---|---|
| DI | references/dependency-injection.md | Injectable dependencies | 依存性注入, DI, mock |
| Pure | references/pure-functions.md | Pure functions, side effect isolation | 純粋関数, 副作用 |
| Mock-Friendly | references/mock-friendly.md | Interfaces, factory patterns | モック, テスト困難 |
| Principle | Application |
|---|---|
| DIP (SOLID) | Depend on abstractions, not concretions |
| Pure Functions | Same input = same output, no side effects |
| Explicit Dependencies | Pass dependencies as parameters |
| Single Responsibility | One reason to test, one thing to mock |
// ❌ Hard to test: Direct dependency
class UserService {
async getUser(id: string) {
return fetch(`/api/users/${id}`).then(r => r.json())
}
}
// ✅ Testable: Injectable dependency
interface HttpClient {
get<T>(url: string): Promise<T>
}
class UserService {
constructor(private http: HttpClient) {}
async getUser(id: string) {
return this.http.get<User>(`/api/users/${id}`)
}
}
// ❌ Hard to test: Side effect mixed with logic
function calculateDiscount(userId: string) {
const history = api.getPurchaseHistory(userId) // Side effect
return history.length > 10 ? 0.2 : 0.1
}
// ✅ Easy to test: Pure function
function calculateDiscount(purchaseCount: number): number {
return purchaseCount > 10 ? 0.2 : 0.1
}
// ❌ Hard to test: Internal state and effects
function SearchBox() {
const [query, setQuery] = useState('')
const [results, setResults] = useState([])
useEffect(() => { api.search(query).then(setResults) }, [query])
return <div>...</div>
}
// ✅ Easy to test: Controlled component
interface SearchBoxProps {
query: string
results: SearchResult[]
onQueryChange: (query: string) => void
}
function SearchBox({ query, results, onQueryChange }: SearchBoxProps) {
return (
<div>
<input value={query} onChange={e => onQueryChange(e.target.value)} />
<ul>{results.map(r => <li key={r.id}>{r.name}</li>)}</ul>
</div>
)
}
generating-tdd-tests - TDD process and test generationreviewing-type-safety - Types improve testabilitytestability-reviewer - Primary consumer of this skill