aaa-pattern について
aaa-patternは、読みやすく保守しやすいテストを書きたい開発者向けのテストスキルです。Arrange・Act・Assertを明確に分け、テスト対象の振る舞いとアサーション数を区別します。
主な機能
- 01Arrange・Act・Assertの分離
- 02各テストで一つの振る舞いを検証
- 03フェーズ混在の兆候を把握
- 04BDD形式のテストにAAAを適用
- 05一つの振る舞いへの複数アサーション
活用シーン
- 01新しいユニットテストの構成
- 02アサーションが散在するテストの整理
- 03理解しにくいテストの原因調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ yanko-belov/ code-craft --skill aaa-patternインストール後、Claude Code で/aaa-patternを入力して読み込まれたか確認します。
詳細
AAA パターン(Arrange-Act-Assert)
概要
すべてのテストには、Arrange、Act、Assert の3つのフェーズがあります。分けて記述してください。
明確な構成にすると、テストの可読性、保守性、デバッグのしやすさが向上します。フェーズが曖昧になると、テストが分かりにくくなります。
使用する場面
- テストを作成するとき
- テストのロジックを追いにくいとき
- 何をテストしているのか不明瞭なとき
- 複数のアクションやアサーションが混在しているとき
絶対に守るルール
EVERY test must have clearly separated Arrange, Act, and Assert phases.
例外はありません:
- 「単純なテストだから」という理由でも
- 「このほうが簡潔だから」という理由でも
- 「フェーズは明らかだから」という理由でも
検出:フェーズの混在という兆候
Arrange/Act/Assert が混在していたら、作業を止めてください:
// ❌ VIOLATION: Phases mixed together
it('adds items to cart', () => {
const cart = new Cart();
cart.add({ id: '1', price: 10 });
expect(cart.items.length).toBe(1); // Assert in the middle
cart.add({ id: '2', price: 20 }); // More acting
expect(cart.total).toBe(30); // Another assert
expect(cart.items.length).toBe(2); // And another
});
問題点:
- 実際には何をテストしているのでしょうか?
- どのアクションがどの結果を引き起こしたのでしょうか?
- テストに正確な名前を付けるのが難しくなります
正しいパターン:明確に分ける
// ✅ CORRECT: Clear AAA structure
it('calculates total price of all items in cart', () => {
// Arrange
const cart = new Cart();
cart.add({ id: '1', name: 'Apple', price: 10 });
cart.add({ id: '2', name: 'Banana', price: 20 });
// Act
const total = cart.getTotal();
// Assert
expect(total).toBe(30);
});
it('tracks number of items in cart', () => {
// Arrange
const cart = new Cart();
// Act
cart.add({ id: '1', name: 'Apple', price: 10 });
cart.add({ id: '2', name: 'Banana', price: 20 });
// Assert
expect(cart.itemCount).toBe(2);
});
3つのフェーズ
Arrange
テストのシナリオを準備します:
- オブジェクトを作成する
- モックを設定する
- 入力データを準備する
- 初期状態を設定する
Act
テスト対象の動作を実行します:
- 通常は単一のアクション
- メソッドを呼び出す
- イベントを発生させる
- リクエストを送信する
Assert
結果を検証します:
- 戻り値を確認する
- 状態の変化を検証する
- モックとのやり取りを確認する
- 副作用を検証する
応用:Given-When-Then
BDD スタイルのテストでも、同じ考え方です:
describe('Cart', () => {
describe('when adding items', () => {
it('should update the total', () => {
// Given (Arrange)
const cart = new Cart();
const item = { id: '1', price: 25 };
// When (Act)
cart.add(item);
// Then (Assert)
expect(cart.total).toBe(25);
});
});
});
テストごとにアサーションは1つだけ?
これはガイドラインであり、ルールではありません。 1つの振る舞いを検証するなら、複数のアサーションを使っても問題ありません:
// ✅ OK: Multiple asserts for one logical behavior
it('creates user with correct properties', () => {
// Arrange
const input = { email: '[email protected]', name: 'Alice' };
// Act
const user = createUser(input);
// Assert - all verify the creation behavior
expect(user.id).toBeDefined();
expect(user.email).toBe('[email protected]');
expect(user.name).toBe('Alice');
expect(user.createdAt).toBeInstanceOf(Date);
});
// ❌ BAD: Multiple behaviors in one test
it('user operations', () => {
const user = createUser({ name: 'Alice' });
expect(user.name).toBe('Alice');
updateUser(user.id, { name: 'Bob' });
expect(user.name).toBe('Bob'); // Different behavior!
deleteUser(user.id);
expect(getUser(user.id)).toBeNull(); // Yet another behavior!
});
プレッシャーに負けないための指針
1. 「このほうが簡潔です」
プレッシャー:「フェーズをまとめれば、テストが短くなります」
回答: 短くても分かりにくいテストより、長くても明確なテストのほうが優れています。
対応: フェーズを分けてください。必要に応じてコメントを追加します。
2. 「単純なテストです」
プレッシャー:「簡単なテストに AAA はやりすぎです」
回答: 一貫性が重要です。すべてのテストで同じパターンに従うべきです。
対応: 単純なテストにも AAA を使ってください。コストはかかりません。
3. 「複数のアクションが必要です」
プレッシャー:「この振る舞いには複数のステップが必要です」
回答: 複数の準備ステップは Arrange に含めます。Act に含めるのは、テスト対象の振る舞いだけです。
対応: Act が複数必要なら、おそらくテストを複数に分ける必要があります。
危険信号 — 作業を止めて見直してください
- アクションの間に
expect()の呼び出しがある - 明確な単一の「Act」がない
- アサーションがあちこちに散らばっている
- テストで何を検証しているか説明しにくい
- テスト名と構成が一致していない
これらはいずれも、AAA を明確に分けて再構成すべきことを意味します。
クイックリファレンス
| フェーズ | 内容 | 例 |
|---|---|---|
| Arrange | セットアップ、モック、データ | const cart = new Cart() |
| Act | 単一の振る舞い | const total = cart.checkout() |
| Assert | 検証 | expect(total).toBe(100) |
よくある誤った正当化(すべて不適切)
| 言い訳 | 実際のところ |
|---|---|
| 「このほうが簡潔です」 | 簡潔さより明確さが大切です。 |
| 「フェーズは明らかです」 | それでも明示してください。 |
| 「単純なテストだから不要です」 | 一貫性が重要です。 |
| 「複数のアクションが必要です」 | テストを複数に分けてください。 |
| 「コメントで十分です」 | コメントより構成のほうが優れています。 |
要点
Arrange、Act、Assert。この順序で、明確に分けてください。
すべてのテストでは、準備を行い(Arrange)、1つのことを実行し(Act)、検証します(Assert)。フェーズが明確であれば、テストの可読性、デバッグのしやすさ、保守性が向上します。