プログラミング
Kent Beck: コンポーザブルテスト
Kent Beck: Composable Tests (newsletter.kentbeck.com)
要約
Kent Beck氏は、テストの「分離」と「コンポジション」という2つの重要な特性について論じています。分離はテストが独立していることを保証しますが、コンポジションは、複数のテストを組み合わせることで、個々のテストだけでは得られない全体的な信頼性を高める方法を示唆しています。冗長なテストを削除し、より簡潔で、より特異的で、変更に強いテストを作成するアプローチを提案しています。
全文翻訳
コンポーザブルテスト
私が思っていたものではありませんでした
Kent Beck
2025年11月10日
47142
共有
テストの要件は、テストに12の特性を要求しており、そのうち2つは次のとおりです。
分離 — 1つのテストを実行した結果は、他のテストの結果から完全に独立している必要があります。
コンポジション — ??? テストは一緒に実行される ??? それは分離と同じことではありませんか?
いいえ、理由はここにあります(ついに例が見つかりました。例は常に最も難しい部分です)。
分離
テストが、独自のテストフィクスチャを設定し、入力として使用するすべてのデータをゼロから作成することから始まる場合、そのテストは分離されていることが保証されます。テストを実行する順序に関係なく、結果はまったく同じになります。(これは関数型プログラミングにおける参照透過性と同じ特性です。)
分離は、xUnitテストフレームワーク(少なくともほとんど)で推奨されています。各テストの前に新しいテストオブジェクトのインスタンスを作成し、setUp() 関数を実行してからテストを実行します。(NUnitなど、一部のフレームワークはテストインスタンスを再利用し、分離を壊す可能性があります。)
コンポジション
分離されたテストのスイートがあり、それらをすべて一緒に実行するとしましょう。スイートの成功は、個々のテスト自体が包括的ではないとしても、私たちに自信(要件の観点から予測可能)を与えるはずです。
例 — テストがあるとしましょう。
test1()
object := new Whatever()
actual := object.doSomething()
assertEquals(expected, actual)
それを機能させて、次の機能ビットを実装したいとします。コピー、ペースト、拡張します。
test2()
object := new Whatever()
actual := object.doSomething()
assertEquals(expected, actual)
actual2 := object.nowSomethingElse()
assertEquals(expected2, actual2)
私はこのようなテストを6〜7回コピー、ペースト、拡張したのを見てきました。最後のテストは読むのが pretty hard です。
test2 が合格しない場合、test1 も合格しないことに注意してください。test1 によって捕捉されるすべての非準拠プログラムは、test2 によっても捕捉されます。同じカバレッジ、同じ予測可能性を維持するために、少なくとも3つの選択肢があります。
両方のテストを残す。
test1 を削除する。
test2 を単純化する。
剪定
純粋に美的観点から(美学を軽視しないでください)、両方のテストをそのまま残すことは私の感性に反します。それらは冗長です!何かが間違っているに違いありません。
test1 を削除すると、テストの要件の別の特性である「テストは具体的であるべき」という特性を失います。これは、テストが失敗した場合に問題がどこにあるかを正確に知ることができるという特性です。
これが私の好む解決策であるコンポジションにつながります。純粋に冗長な部分を避けるために test2 をトリムします。
test2()
object := new Whatever()
object.doSomething()
actual := object.nowSomethingElse()
assertEquals(expected, actual)
test1 + test2 のコンポジションは、予測プロパティを失っていません。特異プロパティも失っていません。実際、test1 が失敗して test2 が合格する可能性があるため(ただし、共通の理由で両方とも失敗する可能性があります)、コンポジションの方が特異性が高くなる可能性があります。
N x M
利息を計算する方法が4つあり、その利息を報告する方法が5つあるとしましょう。これをテストする総当たりアプローチは20のテストです。しかし、コンポジションを使用すると、10のテストでシステムに対する同じ信頼性を達成できます。利息計算のバリアントが、関数型プログラミングの感覚で、報告のバリアントから分離されている場合、次のものが必要です。
計算の4つのテスト
報告の5つのテスト
それらが配線されていることを示すために、計算と報告を組み合わせた1つのテスト
コンポーズされたテストから信頼を得るには、ある程度の思考、推論、設計(直交次元が明らかに直交していることを証明するため)が必要ですが、書くための投資は、テストを次のものにするという点で報われます。
より速く
より読みやすく
変更しやすい
より特異的
構造変更に対する感度が低い
批判
コンポーザブルテストの意味を説明したとき、経験豊富なテスト開発者からショックを受けた反応をよく受けます。「テストのアサーションを減らすことは決してありません。」これは、原則ではなく、恐怖に基づいた反応のように思えます。私たちは、テストを書くこと自体にたどり着くために一生懸命働きました。それらを悪くすることはできません。
コンポジションはテストを悪くすることではありません。コンポジションは、テスト全体を見て、いくつかの価値のあるテストの特性によって判断される全体をより良くしようとすることです。
CodeRabbitでチームのコード品質と出荷速度を向上させましょう — エンジニアのために構築された最も高度なAIコードレビューツールです。CodeRabbitは、コンテキストを理解した行ごとのレビュー、インスタントワンクリック修正、簡潔なPRサマリーを提供し、GitHubワークフローに直接統合されるため、diffの確認に費やす時間を減らし、構築に費やす時間を増やせます。
CodeRabbitは何が違うのか?
CodeRabbitは、チームの標準に適応し、スタイルを強制し、バグやエッジケースを検出し、コード依存関係を自動的にマッピングするAI搭載レビューを提供します。
多言語サポートと40以上のリンターおよび静的解析ツールを備えているため、スタックの複雑さに関係なく、コードをクリーン、安全、保守可能に保ちます。
実際の例は劇的な影響を示しています:SalesRabbitは、すべてのデプロイにCodeRabbitを追加するだけで、バグを30%削減し、エンジニアリングの速度を25%向上させました。
ジュニアおよび経験豊富な開発者の両方を支援するように設計されており、経験豊富なレビュアーが見落とす可能性のある問題もキャッチし、組み込みのドキュメントとレポートは全員を情報に通じ、連携させ続けます。
今すぐCodeRabbitを試す
14日間無料トライアル
CodeRabbitでコードレビュー時間と欠陥率を半分にした何千人もの開発者に加わりましょう。14日間の無料トライアルを開始し、シームレスなAIレビュー、実行可能なフィードバック、簡単なコードベース学習を体験してください。
エンジニアリングワークフローを最適化する準備はできましたか?(CodeRabbitはパブリックリポジトリでは無料です。エンタープライズチーム向けのPro機能も利用可能です。コードレビューを変革するために今すぐ始めましょう)
CodeRabbit提供
47142
共有
前へ
次へ