Development Guidelines
テスト
テスト戦略と各テストの責務・書き方のガイドライン。
方針
統合テスト + E2Eテストの2層構成を基本とする。複雑なロジックに限り、ユニットテストを追加する。
各テストの責務
統合テスト
バックエンドの全層(API → UseCase → Domain → Infrastructure)を通して、APIの入出力とデータの永続化を検証する。
検証すること
- 各エンドポイントの正常系(期待するデータが返ること)
- 異常系のすべてのドメインエラーパス(NOT_FOUND、CONFLICTなど)
- DBにデータが正しく永続化されること(作成・更新・削除の結果)
- 認証・認可(未認証で401、権限不足で403)
検証しないこと
- 入力バリデーション(Valibotスキーマが正しければ保証されるため、二重チェックになる)
- Infrastructure層の内部実装(SQLやDBドライバの挙動はライブラリが保証するため)
- ビジネスロジックの全エッジケース(統合テストは実行コストが高いため、複雑な分岐はユニットテストで検証する)
E2Eテスト
ブラウザを通じて、ユーザーの操作フローが正しく動作することを検証する。
検証すること
- 主要なユーザーフロー(壊れるとビジネスに直接影響する操作)
- 画面遷移(リンク、フォーム送信後のリダイレクト)
- フォーム操作の完了と結果の画面への反映
- エラー時のユーザーへのフィードバック(代表的なケースを1つ)
検証しないこと
- ビジネスロジックの網羅的なエッジケース(E2Eは実行コストが最も高いため、ロジックの網羅は統合テストで行う)
- 異常系の全パターン(統合テストで網羅済みのため、E2Eでは代表的なエラー表示の確認に留める)
- APIレスポンスの構造や値の詳細(統合テストで検証済みのため、二重チェックになる)
- スタイリングやレイアウトの詳細(E2Eテストの範囲外であり、ビジュアルリグレッションツールで検証する)
ユニットテスト
純粋関数や複雑なビジネスロジックを、依存なしに高速に検証する。
書く場面
- 統合テストではカバーが困難な複雑な分岐やエッジケースがある場合のみ
- 例: 複数条件の組み合わせによる計算、日付範囲の重複判定、状態遷移ロジック
検証すること
- 入力に対する出力の正しさ
- 境界値・エッジケース(0、負数、空配列、null等)
- エラーパス(不正な入力に対する例外やエラー値)
検証しないこと
- 単純なgetter/setterやパススルー関数(ロジックがないため、テストしても信頼性が上がらない)
- 実装の詳細(リファクタでテストが壊れる原因になるため、振る舞いのみを検証する)
- 外部ライブラリの動作(ライブラリ側で検証済みのため、二重チェックになる)
テスト名の書き方
テスト名は、失敗したときにテスト名だけで何が壊れたかわかるように書く。
形式
- 条件なし:
{期待する振る舞い} - 条件あり:
{条件}の場合、{期待する振る舞い}
例
// 統合テスト
describe('employee.create', () => {
it('従業員を作成し、IDを返す');
it('メールアドレスが重複している場合、CONFLICTエラーを返す');
});
// E2Eテスト
test.describe('従業員管理', () => {
test('従業員を新規作成すると、一覧に表示される');
test('存在しない従業員にアクセスすると、404ページに遷移する');
});避けるべき書き方
正しく動く— 何が正しいのか不明エッジケースを処理する— どのケースか不明createEmployee test— 英語のテスト名は日本語プロジェクトでは読みにくい