mcpField
A
aaa-pattern

aaa-pattern

github.com/yanko-belovテスト・品質1341 回インストール40 週間前に更新
リポジトリ

aaa-pattern について

aaa-patternは、読みやすく保守しやすいテストを書きたい開発者向けのテストスキルです。Arrange・Act・Assertを明確に分け、テスト対象の振る舞いとアサーション数を区別します。

主な機能

  1. 01Arrange・Act・Assertの分離
  2. 02各テストで一つの振る舞いを検証
  3. 03フェーズ混在の兆候を把握
  4. 04BDD形式のテストにAAAを適用
  5. 05一つの振る舞いへの複数アサーション

活用シーン

  1. 01新しいユニットテストの構成
  2. 02アサーションが散在するテストの整理
  3. 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)。フェーズが明確であれば、テストの可読性、デバッグのしやすさ、保守性が向上します。

コメント