[フレーム]
BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

InfoQのすべての体験をアンロックして、そのメリットを最大限に活用しましょう

ログインして、InfoQのすべての体験をアンロックしましょう!お気に入りの著者やトピックの最新情報を入手し、コンテンツと交流し、限定リソースをダウンロードできます。

ログイン
または

アカウントをお持ちでない方

登録
  • あなたにとって重要なトピックや同僚の最新情報を入手しましょう最新の洞察とトレンドに関する最新情報を即座に受け取りましょう。
  • 継続的な学習のために、無料のリソースに手軽にアクセスしましょうミニブック、トランスクリプト付き動画、およびトレーニング教材。
  • 記事を保存して、いつでも読むことができます記事をブックマークして、準備ができたらいつでも読めます。

Topics

地域を選ぶ

AIオールスターズ2025

"AI活用"をキーワードに「AIを使い倒し/使いこなす」企業の最前線をお届けします。

QCon San Francisco - image
QCon San Francisco 2025

Get production-proven patterns from the leaders who scaled a GenAI search platform to millions, migrated a core ML system without downtime, and architected a global streaming service from the ground up.

Early Bird ends Nov 11.

QCon AI New York - image
QCon AI New York 2025

Move beyond AI demos to real engineering impact. Discover how teams embed LLMs, govern models, and scale inference pipelines to accelerate development securely.

Early Bird ends Nov 11.

QCon London - image
QCon London 2026

Benchmark your systems against leading engineering teams. See what really works in FinOps, modern Java, and distributed data architectures to balance cost, scale, and reliability.

Early Bird ends Nov 11.

InfoQ ホームページ アーティクル シンプルなテストピラミッドの提案 ~ テストを有効活用するためのイロハ

シンプルなテストピラミッドの提案 ~ テストを有効活用するためのイロハ

2023年6月13日 読了時間 11 分

キーポイント

  • テストの効果は、テストを書くコストや、実行コスト、維持コストを上回るべきである。
  • 遅いテストは、時間の経過とともに、テストスイートのコストの最大要因の1つになる傾向がある。
  • テストスイートの期間を少し短縮するだけでも時間の節約に貢献する。
  • テストコードのリファクタリングは、プロダクションコードのリファクタリングと同じレベルで注意すべきである。
  • 時間がかかりすぎるテストスイートは実行時にビルドを失敗させるようにする。

テストラベル

開発者は自動テストを書くためにさまざまなラベルを使っている。例えば単体、統合、受け入れ、コンポーネント、サービス、E2E、UI、データベース、システム、機能、または APIなどなど。これらのラベルにはそれぞれ異なる意味があり、テストのスコープ、アクションの種類、テスト対象、またはテスト対象のコラボレーターのいずれかを表している。私たちはたいていラベルのそれぞれの意味について共通言語化しておらず、定義に関する無駄な議論を延々と繰り広げてしまうこともしばしばである。

私は、どのラベルを使うか、どのように定義するかを議論するよりも、それぞれのテストに単純に「遅い」「速い」というラベルをつける方が役に立つと考えている。この考え方はテストスイートの構成を決めるときにも有効で、開発者は非生産的な議論をせずとも、客観的にテストを分類できるからだ。

    関連スポンサーコンテンツ

テストラベルの選択はテストスイートの構成に重要な影響を及ぼす。開発者は与えられたふるまいに対して、いつテストを書くべきか、どのタイプのテストを書くべきか、そしてテストスイート全体のバランスを評価するためにテストラベルを使用する。これを誤ると、正確ではないカバレッジのテストスイート、もしくはカバレッジは担保するが受け入れがたいコストのテストスイートを作ってしまうことに成りかねないのである。

テストを書くべき時

プロダクションコードに対して、いつテストを書くべきだろうか?私のようにエクストリームプログラミング(XP)やテスト駆動開発(TDD)を実践している開発者は、この問いに対して「常に(Always)」と答えがちである。しかしながら、すべてのコードのテストは自動化するべきではないし、それぞれのテストについて、まずテストの作成コストとメリットを比較して進めるべきなのである。

私はテストを書くことに反対しているわけではない。実際ほとんどのテストはこのチェックの答えが「はい」になるだろう。このチェックは実行に時間がかかるテストや、書くのに時間がかかるテスト、あるいはメンテナンスが難しいテストに有効である。試しに自分自身にいくつかの質問を投げてみると良い。

Q そのテストにコストを要するのは、設計上の判断によるものなのか?
Q テストのためにコードをリファクタリングすることは可能か?

テストはプロダクションコードの最初の利用者である。コードをテストしやすくすることで、コードを利用しやすくなり、コードの品質が向上することは頻繁に起こることだ。

Q そのテストは、テスト手法のせいでコストを要するのか?
Q 別のテストアプローチならば、もっと簡単に書けるだろうか?

コラボレーターの代わりに、フェイクやモックのようなテストダブルを使うことを検討する。テストに複雑な設定が必要な場合は、これをテストシナリオに抽出しテスト間で再利用できるようにする。

テストダブルの過度な利用に注意すべきである。理由は本物のコラボレーターほどの信頼性は得られないからだ。たしかにフェイクやモックを用いたテストは、セットアップの容易さ、テスト期間の短縮、個々のテストの信頼性の向上といった観点で見合う場合もある。しかしテストダブルに頼りすぎるとテストと実装が一体化してしまい、全体としてリファクタリングを阻害する信頼性の低いテストスイートになる可能性があるのだ。

Q 本質的にテストが難しいためにテストのコストを要するのか?

こういった場合はテストしている機能の重要性を考慮する。例えば、支払い処理に関わる重要な機能であれば、かかるコストは妥当かもしれないしディスプレイロジックのエッジケースならば、テストが本当に必要であるかどうか再考すべきである。

Q 予測できない失敗をするテストにコストを要していないだろうか?

もしそうならばテストを削除するか、信頼性の高いテストに書き直すか、テストスイートを分離すべきだ。テストスイートが有用なフィードバックを提供するためには、テストの失敗が望ましくない動作であることを確信するべきだ。予測ができないが必要なテストならば、実行頻度の低い別のテストスイートに移動すべきだろう。

テストピラミッド

開発者はいつテストを書くか、そしてどのような種類のテストを書くかを決めるのに、テストのラベルをテストピラミッドに置いて特定のテストタイプの重要度を伝えることがある。

テストを説明するために使われるラベルの種類が多いため、テストピラミッドの形はケースバイケースで少しずつ異なる。「テストピラミッド」で画像検索してみると、最初のページでは数個のピラミッドが似た結果となるだろう。それぞれのピラミッドは一般的に一番下に低コストの単体テスト、一番上に高コストのシステムテスト、そして真ん中に中くらいのコストのテストが何層にも重なっている。

テストピラミッドを活用する前に、チームはテストピラミッドにどのラベルを含めるか、それぞれのラベルの定義は何か、ピラミッドにどのような順序でラベルを含めるかを決定するべきである。なぜなら開発者は独自のテストのためのラベルセットを持つ傾向があり、各ラベルが何を意味するかについてチーム内(またはチーム間)で包括的な合意がないからだ。

ほとんどのテストピラミッドで最下段は単体テストだが、「単体(Unit)」という言葉が何を指すのかについては、残念ながら大きな認識の不一致が存在する。この意見の相違は、テストスイートのコストを削減することよりもラベルに関する議論になりがちであり、テストスイートの有用性が低下してしまうのである。

スピードにこだわる

スピードはテストスイートの運用コストにもっとも寄与する。迅速なフィードバックのために開発者はテストスイートを1時間に複数回実行する必要があるため、スイートの実行時間がわずかに増えるだけでも、結果として長時間の待機時間につながることがあるのだ。

テストの実行待ちは極めて非生産性的な時間である。テストスイートが非常に遅い場合(5分以上かかる場合)、開発者はテストの実行中に他のタスクに取り組むことがよくある。このタスクスイッチは有害であり、集中力を減少させ開発者がコンテキストを失う結果になる。時間のかかるテストスイートが終了した後、開発者は元のタスクを再開する際に復帰のための時間を要するのである。

より良いピラミッド

テストの速度にこだわると、もっとシンプルなテストピラミッドが求められる。

このピラミッドはテストスイートにはできるだけ多くの高速テストと目的のふるまいを完全にカバーするのに十分な低速テストが必要だという明確なメッセージを伝えている。一般的な(そして複雑な)テストピラミッドと同じメッセージだが、開発者が理解し、同意するのは非常に簡単である。

とあるテストを一般的なテストピラミッドのどこに配置するかは、開発者によって意見が分かれるかもしれないが、あるテストがこのピラミッドのどこに当てはまるかは簡単である。チームはどれが速いテストであるか、どれが遅いテストであるか、に合意するだけである。ビジネスドメイン、言語、フレームワークによって閾値は異なるかもしれないが、テストの速度は客観的に測定できるからである。

高速なテストスイート

テストスイートは初期段階では高速だが、その状態を維持することは稀である。時間の経過とともにテストが追加され、開発者は遅いテストスイートに対する許容範囲を広げていく。開発者の多くはテストスイートを高速に保つプロダクトの経験がないため、高速なテストスイートが実現可能であることに気づいていないのだ。

テストスイートを高速に保つには訓練が必要である。開発者はテストスイートを追加するときはいつでも精査し、わずかなテスト時間の短縮でも得られる効果を認識するべきである。例えば6人の開発者からなるチームの1人が、テストを10秒速くするために4時間を費やした場合、その投資はわずか6週間で償却できるのだ(開発者が1日のうち1時間に1回テストを実行すると仮定)。

制限を設ける

チェックを外すと、テストスイートの長さは時間の経過とともに指数関数的に増加する。つまり長さは現在の継続時間に比例して長くなる。テストスイートが10秒で完了するならば、開発者はビルド時間が1秒増えることに悩むかもしれないが、テストスイートに3分かかる場合はそのことに気づかないかもしれないのだ。

テストスイートの実行時間が1分以上かかる場合はビルドを失敗させるなど、指数関数的な増加を防ぐ方法として、テストスイートの実行時間に厳しい制限を設けるべきである。テスト実行に時間がかかりすぎるとビルドは失敗するので、開発者はテストを高速化するために時間をかけなければならなくなる。そして制限時間を長くしてビルドを修正することを許してはいけない。なぜテストが遅いのかどうすれば速くできるのかを理解するために時間をかけて考えてもらうのである。

リファクタリング

テストコードはプロダクションコードと同様の注意と検証が必要である。テストコードを適切に構造化し高速に保つために継続的にリファクタリングを行い、テストスイートの維持と実行のコストを最小にする。テストのリファクタリングではテストコードやプロダクションコードのふるまいを変更してはいけないということを念頭におき、むしろ可読性、保守性、実行速度を向上するように、コードを修正することが求められるのである。

どうしても遅いテストがあるならば、異なるテストスイートに分離する。この遅いテストスイートは、メインのテストスイートのように頻繁に実行するものではなく、追加のカバレッジを提供するために存在するものと考える。ビルドプロセスをブロックしてはいけないが、テスト対象のふるまいが正しく機能していることを、検証するために定期的に実行する。

既存のテストスイート

もし読者のみなさんが現在、別のテストピラミッドを採用していたとしても、アプローチの変更をするには遅すぎるということはない。みなさんが複雑なテストピラミッドに従っているのなら、テストの多くはピラミッドのラベル名を含んでいると考えられるからだ。

最初の一歩として、テスト名を変更する時間をとってもらいたい。新しいテスト名は、テストのラベルではなく、テストするふるまいを反映させるのである。たとえば、UserIntegrationTest を UserAuthenticationTest に、RegistrationApiTest を AddPaidUserTest といった具合である。

このプロセスでは、新しい名前の間でいくつかの衝突が発生する可能性がある。この衝突は同じふるまいを検証する複数のテストが存在するという警告そのものである。重複を解消するために、これらのテストの移動、結合、名前の変更、または削除をじっくりと実施するのである。

テストの名前を変更したら、テストのディレクトリ構造を再編成し、ふるまいに従ってテストをグループ化する。こうやって整理することで、コード上で同時にふるまうテストの関連性を見出して重複するふるまいを検証するテストを発見するのに役立つのである。

遅いテストスイート

遅いテストスイートはすぐに対処するべきである。さらに遅くならないように、すぐにテストスイートの実行時間に制限を設ける。次に、各テストまたはテストグループの実行時間をリストアップして、遅いテストを検知する計測器を追加する。このプロセスで容易に高速化できるテストがいくつか見つかるはずである。

これらを修正すれば改善が難しい遅いテストが残る。高速テストをスイートから分離し、残りの低速テストとは別に実行できるようにする。こうすることで、一部のテストはすぐにスピードアップし、改善のための時間を確保できるのである。

定期的にテストのスピードアップに時間を割くようにする。遅いテストでカバーされているふるまいが、より速いテストでカバーできる(あるいはすでにカバーされている)かどうかを調査するのである。よくある例としては、ブラウザを動かすテストで多くのエッジケースをカバーすることが挙げられる。ブラウザのテストは時間を要するので、もっと高速な低いレベルのテストでその検証を代替できることが多い。

実践にむけて

システムテストと統合テストのどちらを書くか議論するならば、その前に少し考えてもらいたい。その2つの区別が、さほど重要ではないことに気づくのではないだろうか。コストを最小限に抑えながら高い信頼性を得ることが目的であれば、いかに低コストで目的のふるまいをテストできるかを議論することになる。この方向で議論を進めれば、より生産的な結果を得られるのである。

テストのラベルばかりに注目するのではなくもっと重要なことに注目すべきである。テストが遅いのならば速くする。それが難しい場合は、かわりに狭いスコープのテストで同じカバレッジを提供することを試みる。それができないならばテストの効果が、遅いテストに要する多大なコストに見合うかどうかを検討する。その価値があるならば、ビルドを妨げない別のテストスイートに遅いテストを分離することを検討するのである。

新しいテストピラミッドに従って、テストのスピードにこだわって、テストスイートを高速化し、信頼性を高く保つようにしてもらいたい。

作者について

Tyson Gern

もっと見るより少なく

この記事に星をつける

おすすめ度
スタイル
  • 関連記事

トレンド

特集コンテンツ一覧

InfoQ ニュースレター

毎週火曜日に前週のまとめコンテンツをお送りいたします。(日本語版は不定期リリース)25万人のシニアな開発者コミュニティーにぜひご参加ください。 サンプルを見る

We protect your privacy.

BT

AltStyle によって変換されたページ (->オリジナル) /