takt/builtins/en/stances/testing.md
nrslib ea7ce54912 takt: # タスク指示書: resources/ → builtins/ リネーム + export-cc 修正
## 概要
`resources/` ディレクトリを `builtins/` にリネームし、用途を明確化。同時に export-cc コマンドを拡張して全リソースをコピーするように修正する。

---

## タスク一覧

### 1. ディレクトリリネーム(優先度: 高)

| 変更前 | 変更後 |
|--------|--------|
| `resources/` | `builtins/` |
| `resources/global/{lang}/` | `builtins/{lang}/`(global/ 階層を除去) |
| `resources/project/` | `builtins/project/` |
| `resources/skill/` | `builtins/skill/` |

### 2. 不要ファイル削除(優先度: 高)

- `builtins/{lang}/prompts/` を削除
  - 対象: `interactive-system.md`, `interactive-summary.md`
  - 理由: コードから未参照、実体は `src/shared/prompts/`

### 3. コード修正 — パス参照(優先度: 高)

`resources` → `builtins`、`global/{lang}` → `{lang}` に更新:

| ファイル | 修正内容 |
|----------|----------|
| `src/infra/resources/index.ts` | `getResourcesDir()`, `getGlobalResourcesDir()`, `getLanguageResourcesDir()` 等のパス |
| `src/infra/config/paths.ts` | `getBuiltinPiecesDir()`, `getBuiltinPersonasDir()` |
| `src/infra/config/global/initialization.ts` | `copyLanguageConfigYaml()` |
| `src/infra/config/loaders/pieceCategories.ts` | `getLanguageResourcesDir()` 参照 |
| `src/features/config/ejectBuiltin.ts` | `getLanguageResourcesDir()` 参照 |
| `src/features/config/deploySkill.ts` | `getResourcesDir()` 参照 |

### 4. export-cc 修正(優先度: 高)

ファイル: `src/features/config/deploySkill.ts`

**現状**: pieces/ と personas/ のみコピー

**修正後**:
- `builtins/{lang}/` 全体を `~/.claude/skills/takt/` にコピー
- `skill/` のファイル(SKILL.md, references/, takt-command.md)は従来通り
- サマリー表示を新リソースタイプ(stances, instructions, knowledge 等)に対応
- confirm メッセージ修正:
  - 現状: `'上書きしますか?'`
  - 修正後: `'既存のスキルファイルをすべて削除し、最新版に置き換えます。続行しますか?'`

### 5. テスト修正(優先度: 中)

| ファイル | 修正内容 |
|----------|----------|
| `src/__tests__/initialization.test.ts` | `getLanguageResourcesDir` のパス期待値 |
| `src/__tests__/piece-category-config.test.ts` | mock パス |
| その他 `resources` パスを参照しているテスト | パス更新 |

### 6. ビルド・パッケージ設定(優先度: 中)

| ファイル | 修正内容 |
|----------|----------|
| `package.json` | `files` フィールドで `resources/` → `builtins/` |
| `tsconfig.json` | `resources/` への参照があれば更新 |
| `.gitignore` | 必要に応じて更新 |

### 7. ドキュメント(優先度: 低)

- `CLAUDE.md` の Directory Structure セクションを更新
- JSDoc コメントから `prompts/` 記述を削除

---

## 制約

- `builtins/{lang}/` のフラット構造は変更不可(ピースYAML内の相対パス依存)
- eject のセーフティ(skip-if-exists)は変更不要
- export-cc のセーフティ(SKILL.md 存在チェック + confirm)は維持

---

## 確認方法

- `npm run build` が成功すること
- `npm test` が全てパスすること
- `takt init` / `takt eject` / `takt export-cc` が正常動作すること
2026-02-07 14:46:20 +09:00

2.9 KiB

Testing Stance

Every behavior change requires a corresponding test, and every bug fix requires a regression test.

Principles

Principle Criteria
Given-When-Then Structure tests in 3 phases
One test, one concept Do not mix multiple concerns in a single test
Test behavior Test behavior, not implementation details
Independence Do not depend on other tests or execution order
Reproducibility Do not depend on time or randomness. Same result every run

Coverage Criteria

Target Criteria
New behavior Test required. REJECT if missing
Bug fix Regression test required. REJECT if missing
Behavior change Test update required. REJECT if missing
Edge cases / boundary values Test recommended (Warning)

Test Priority

Priority Target
High Business logic, state transitions
Medium Edge cases, error handling
Low Simple CRUD, UI appearance

Test Structure: Given-When-Then

test('should return NotFound error when user does not exist', async () => {
  // Given: A non-existent user ID
  const nonExistentId = 'non-existent-id'

  // When: Attempt to fetch the user
  const result = await getUser(nonExistentId)

  // Then: NotFound error is returned
  expect(result.error).toBe('NOT_FOUND')
})

Test Quality

Aspect Good Bad
Independence No dependency on other tests Depends on execution order
Reproducibility Same result every time Depends on time or randomness
Clarity Failure cause is obvious Failure cause is unclear
Focus One test, one concept Multiple concerns mixed

Naming

Test names describe expected behavior. Use the should {expected behavior} when {condition} pattern.

Structure

  • Arrange-Act-Assert pattern (equivalent to Given-When-Then)
  • Avoid magic numbers and magic strings

Test Strategy

  • Prefer unit tests for logic, integration tests for boundaries
  • Do not overuse E2E tests for what unit tests can cover
  • If new logic only has E2E tests, propose adding unit tests

Test Environment Isolation

Tie test infrastructure configuration to test scenario parameters. Hardcoded assumptions break under different scenarios.

Principle Criteria
Parameter-driven Generate fixtures and configuration based on test input parameters
No implicit assumptions Do not depend on a specific environment (e.g., user's personal settings)
Consistency Related values within test configuration must not contradict each other
// ❌ Hardcoded assumptions — breaks when testing with a different backend
writeConfig({ backend: 'postgres', connectionPool: 10 })

// ✅ Parameter-driven
const backend = process.env.TEST_BACKEND ?? 'postgres'
writeConfig({ backend, connectionPool: backend === 'sqlite' ? 1 : 10 })