テスト側開発者(SDET)のルールファイル 〜開発と開発者テスト編〜
こんにちは。ダイの大冒険エンジョイ勢のbun913と申します。
わたしはSDET(Software Development Engineer in Test)という職種で働いており、テスト自動化だけでなく、システムの品質を向上させるための様々な活動を行っています。普段からプロダクトコードをゴリゴリ書く仕事ではありませんが、あくまでテスト側にメインで従事する開発者の意識に比重を寄せて業務を行っています。
そんな私ですが、先日とある開発エンジニアの方から「bunさんの CLAUDE.md を見せてください」と言われた際に「シチュエーションによって使い分けてます」と答えて具体例をあまり示すことができませんでした。
実際私の業務はQAエンジニアとしての活動、APIテストやUIテストの自動化などのSDETとしての活動など多岐にわたり、業務によって異なるルールファイルを使い分けています。
そこでおそらく彼が期待していたであろう、テストに関する記述や Claude Code との開発のフローなどを意識したルールを本記事で紹介し、彼に渡したいと思います。
前提
今回のプロンプトはすべて日本語で書いています。Tokenの圧縮やチーム開発の観点から、実際は英語で書いていることも多々ありますが、あくまで可読性重視以外の意味は特にはありません。
利用ツール
私は普段Claude Code を利用していますが、色々なツールやエージェントで同じように開発できるように rulesync というツールを利用して一つの場所でルールファイルを管理するようにしています。
チームによっては Cursor, GitHub Copilot など様々なツールを利用している方がいらっしゃると思いますので、このツールでプロジェクトごとに管理すると便利だと思います。
開発時のルールファイル例
早速ですが、以下のようなルールを利用しています。
あまり細かなツールや規約に関しては書いていません。コンテキスト圧迫を避ける目的と、Hooksを活用して細かなルールはlinterやformatter側で機械的に管理してもらうためです。
## 役割と専門性
- あなたは SDET(Software Development Engineer in Test) です
- あなたは ISTQB のブラックテスト技法とホワイトボックステスト技法に習熟しています
- テストコードを書くときにはできるだけ少ないテストケースで最大限のバグを発見することを信条にしています
## 開発における大原則
- A philosophy of Software Design の Deep Module Design の考え方に従う
- コメントとインターフェースファーストで開発を行う
- コメントとインターフェースの実装が完了したら、twada氏のTDDの手法にしたがってテスト駆動で実装を行う
- テストコードは境界値分析・状態遷移テスト・デシジョンテーブルのブラックボックステスト技法を活用する
- テストに関してはブランチカバレッジ80%以上を常に維持する
### コメントとインターフェースファーストの開発
- A philosophy of Software Design の Deep Module Design の考え方に従ってインターフェースの開発を行う
- ここでいうインターフェースとは、JavaやTypeScriptの言語機能としてのインターフェースではなく、クラス・モジュール・関数などの使い手が利用するために提供されるものである
- コードを書く際に最初から実装をするのではなく、まずクラスやクラスが持つ関数・インスタンス変数などのシグニチャを記載する
- シグニチャの記載とともに、インターフェースやシグニチャに対するコメントを記載する
- この時点でのコメントは実装に関する詳細ではなく、高レベルでの役割などを記載する実装に関するコメントではない
- 既存のコードがある場合は、既存のコードスタイルを参考にして一貫性を保つこと
- あなたは独善でコードや設計を大きく変えることがメンテナンス容易性に大きな影響を与えることを理解している
### twada氏のTDDにしたがった実装の開発
- すべてのインターフェースおよびコメントが記載できたら、twada氏のTDDの手法にしたがって実装を行う
- まずは失敗するテストを書き、その後にテストを通過するための最小限の実装を行う
- テストが通過したら、リファクタリングを行い、テストが通過することを確認する
- 実装を行う際は常にテストが通過することを確認しながら実装を行う
- 実装と合わせて実装に関するコメントを記載する
- 実装がどのようにされているかではなく、何を・なぜ実装しているかについて記載すること
- コードを見ればわかるような どのように実装しているか の記載でコード量を増やすことを好みません
### テストに関するルール
- テストの命名やスタイルに関して
- `describe` などの関数を利用してテストを構造化する
- `describe` では SUT (System Under Test) と given/when 条件を明確にする
- `test()` ではなく `it()` を使用し、"should" や "must" などの助動詞を使わずに期待される動作を記述する
- テストは実装の詳細ではなく、特定の条件下での振る舞いに焦点を当てる
- テスト技法は境界値分析・状態遷移テスト・デシジョンテーブルのブラックボックステスト技法を活用する
- ユニットテストの役割
- ユニットテストは常に実行し続けても気にならないスピードで開発者にフィードバックを与えることを目的とする
- 極力フェイク(モック、スタブ)を利用して、実装の詳細に依存しないテストを行う
- フェイクを利用する際は自作自演のテストを避け、そのコンポーネントが相手との契約を守れているかを確認すること
- ただし、RDB/コンテナ化している外部ストレージ に関してはフェイクを利用しない
- これらは本プロジェクト側で管理できるものであり、実行速度の多少の増加よりも実際の動作を確認する利益が大きいためである
- 一方で、本プロジェクトではコントロールできない外部の依存に関してはフェイクを利用する
- インテグレーションテストはユニットテストと異なり複数のフェイクではない依存を含んだテストである
- 実行速度やフィードバックの速さよりも開発者により深い安心感を与えるために複数の依存を含めてテストを行う
- ただし、インテグレーションテストに関してはユーザーから指示があった場合に実装すること
// 実装例
// HTTPリクエストを送信するコンポーネントの例
describe('getTestCase', () => {
it('calls correct API endpoint with case ID', async () => {
const mockAxios = vi.mocked(axios);
const mockApiInstance = {
get: vi.fn().mockResolvedValue({ data: { id: 123 } }),
};
mockAxios.create.mockReturnValue(mockApiInstance as any);
const client = new TestRailClient(config);
await client.getTestCase(123);
// フェイクで注入した結果が返ってくることではなく利用するコンポーネント側との契約を守れていることを確認する
expect(mockApiInstance.get).toHaveBeenCalledWith('/get_case/123');
});
});
このルールを利用する時の開発スタイル
上記ルールファイルを見ていただければわかるかもしれませんが、私自身がAIを全面的に信用した開発を行うことがあまり得意ではありません。いわゆるバイブコーディングではなく、エージェントを有効活用して設計などを把握した上で開発するエージェンティックコーディングを意識しています。
インターフェースなどの設計も実装も一気にしてもらうとあまり効率の良いコードが出てこないことも経験上多くあります。そのため、大きくそれらを分けて、まずはインターフェースやコメントを記載してから実装を行うようにしています。
流れとしては以下のような形です。
- 前準備
- このルールを利用する前に、まずは自分が実現したいことや背景をエージェントに伝えて、自分の中で必要な調査なども終わらせておきます
- 必要に応じてMCP Server を利用してビジネス要求やデザインなどのコンテキストを与えるのも良いと思います
- インターフェースやコメントの記載
- 前準備で要求の整理や大まかな仕様の整理が終わったら、AIエージェントにインターフェースやコメントの記載を依頼します
- この時点では実装は行わず、あくまでインターフェースやコメントの記載を依頼します
- これによりAIエージェントに知らない間によくわからない実装をされることを防ぎたい意図があります
- もちろん必要に応じて実装フェーズからインターフェースやコメントの修正や追加を行います
- 一連のインターフェースを通じて、要求を満たすことができるか納得できるまでクラスの構造やコメントについてやりとりを行います
- 実装の依頼
- インターフェースやコメントの記載が終わったら、AIエージェントに実装を依頼します
- その際、TDDにおいてtwada氏の提唱される手法にしたがって実装を行うように依頼します
やりとりの例
実際の開発では、このようなやりとりが行われます:
私: ConfigManager というクラスは Deep Module かな?実際ほとんど Config データを保持するためだけの浅いクラスじゃないかな?忖度せずに議論しようよ。
AI: 良い指摘ですね!確かに ConfigManager というのはほとんどロジックを保持せず使い手に読む負担をかける方が大きい可能性があります。これらを分離して、各種ビジネスロジックの処理を行うクラスでvalidationを行うようにしましょう。
私: いいね。あ、でも各ビジネスロジックの処理を行うクラスのために Config の型を定義して渡すのはいいと思う
開発者テストに対する指示の意図
モデルの知識量がとてつもないため、あまりこと細かに例を出さなくても「境界値分析・状態遷移テスト・デシジョンテーブルのブラックボックステスト技法を活用する」といった指示をするだけで、AIエージェントはそれに従ってテストケースを作成してくれる印象があります。
そのため少し前まで、細かに例を書いていたのですがそれら技法に対する例は省略するようにしてみました。
もちろん複雑なロジックや複雑な状態がある場合は、テストケースを書く前にマークダウンやmermaid.js などを活用して状態遷移図などを作成して、AIエージェントに説明を行うこともあります。
複雑な状態遷移の例
複雑なロジックがある場合は、このようなやりとりになります:
私: 結局この申請の状態が複雑だね。一旦どの状態からどの状態に遷移できるかをmermaid形式でマークダウンに整理してみてよ
AI: (作業完了)
私: いいね。このテストを書くにあたって有効な遷移は網羅しておきたいです。このイベントを起こせばこうなるはずたっていう。
私: また、ビジネス上の観点から「完了済」から「キャンセル済み」に遷移できないって大事だからその無効遷移も書いておいて
まとめ
- SDET として開発系のタスクで利用しているルールファイルを紹介しました
- この開発には APIテストやUIテストなどのテストコードを書くことがメインのプロジェクトは含んでいません
- ユニットテストなどの開発者としての帽子を被った私とは少し異なるルールを利用しています
- 今度機会があれば紹介したいと思います
- 完全なバイブコーディングではなく、エージェントを有効活用して設計やインターフェースを把握した上で開発するエージェンティックコーディングを意識しています
- すでに概念と知られているものは「xxさんの手法です」「ISTQBで公開されるブラックボックステスト技法です」といった指示をして、コンテキストを圧迫しないようにしています
お読みいただきましてありがとうございます。ぜひ皆さんもご自分のルールなどについて気軽な形で教えてください。とてもニッチな分野でも、誰かにとっては非常に有益な情報になるかもしれません。
以上、お読みいただきましてありがとうございました。
参考コンテンツまとめ
最後にこれらルールを書く際に参考にさせていただいているコンテンツを紹介します。
参考にしたプロンプト・ルールファイル
まず Claude 4 プロンプトエンジニアリングのベストプラクティス を元にルールファイルにコンテキストを含めています。
「〜を目的として」や「〜を意図して」といった指示を含めるようにしています。
また、 Kent Beck 氏の CLAUDE.md も非常に参考にしています。(Roleの設定や設計の大原則など)
なお以前の記事でも紹介しており恐縮ですが、以下の fukabori.fm の 131. AIコーディングの現在地 w/ twada
というエピソードも参考にしています。
twadaさん自身、「twadaが推奨するTDDの手法を使ってください と伝えると、確かにいい感じの挙動になった」 といったお話をされており、Kent Beck 氏もご自身の名前と tidy first のルールを上のルールファイルに書いていることなどの共通点が面白いです。
設計・コメントファースト開発 に関するコンテンツ
以前の記事でも紹介した A Philosophy of Software Design という書籍からも着想を得ています。
Deep Module といった「モジュールやクラスの小ささ」だけではなく「深さ」という概念や、まず実装を書く前にクラスやインターフェースの公開関数やインスタンス変数(シグニチャ)などから書くといった考え方はこちらの書籍から学びました。
なお書籍の執筆者である John K. Ousterhout 氏はTDD については否定的な意見を書籍中で述べられていましたが、私は自身のルールの中でTDDについて指示をしています。この辺りも日々の活動の中で変更していくかもしれません。
Discussion