Ccmmutty logo
Commutty IT
6
0 pv5 min read

自動テスト戦略:テストピラミッド

https://cdn.magicode.io/media/notebox/15cc213c-c216-4b97-ba3d-5f3b6ff8c93d.jpeg
テックリードとして2つのプロジェクトのテスト自動化を推進しています(本業)。
この記事では、プロジェクトでの経験を踏まえ、テスト自動化の最重要戦略「テストピラミッド」について紹介します。

この記事の目的

  • これから新規/既存Webシステムのテストを自動化する人に向けて、テスト自動化の成功を支える戦略「テストピラミッド」について、筆者の経験を交えて紹介する
「テスト自動化なんて、とりあえずcypress書けばいいのでは?」と思った方は、ぜひこちらの記事を先に読んでいただけると嬉しいです。

1. 自動テストの全体像

Webサービス単体に絞ると、自動テストの種類は概ね3つに分かれる。 ※1
  • 内部仕様
    • ユニットテスト:xUnitやjestなど、テストコードで実現
  • 外部仕様
    • APIテスト:サーバーを起動し、HTTPリクエストを送ることで検証する。テストコードで実現する場合もある
    • UIテスト:サーバーを起動し、ブラウザを自動操作することで検証する。
以下に、Webサービス単体における自動テストの大まかな種類を図示する。
※1:一般に、システム全体は複数のWebサービスが連携することで構成される。Webサービス間をまたがるテストを含めると、E2Eテストなどもある。分かりやすくするため、この記事ではWebサービス単体にフォーカスする。

補足:外部仕様・内部仕様とは

ここでいう外部仕様内部仕様とは、以下のようなものである。
  • 外部仕様
    • システムの外側から見た仕様。インターフェース仕様。
    • 例えば、UIの仕様。どのような見た目をしているかや、どのリンクを押したらどの画面に遷移し、ボタンを押すと何が起きるかなど
    • 例えば、APIの振る舞い。リクエストに対してどのようなデータが生成され、どういうレスポンスが返るかなど
  • 内部仕様
    • 外部仕様を実現するための内部的な実装全て。
    • 例えば、ソースコードの書き方。どのモジュールからどのモジュールを呼び出すことで機能を実現しているかなど
    • 例えば、データベースの構造。テーブル間の関連や、テーブルのカラム名など

2. 【本題】自動テスト戦略:テストピラミッド

結論

自動テストを効果的に行うために、以下のことが重要である。
  • 大きな粒度のテスト(例えばAPIやUIテスト)は、控えめにしておく。
  • 心の拠り所として、より小さな粒度のテスト(例えばユニットテスト)に注力する。
※解説後、図解とともに再掲する。

課題定義

一般に、大きい粒度のテストは、よりコストがかかり、より遅い。
技術スタックにも依るが、筆者の推進しているプロジェクトでは、概ね以下のような結果が出ている。
  • コスト:ユニットテストは1ケースは数分で書けるが、UIテストやAPIテストは1ケース作るのに30分〜1時間かかる。
  • 実行時間:ユニットテスト100ケース10秒で終わるが、UIテスト30ケースは15分かかる。APIテスト30ケースは1分かかる。
何より、大きい粒度のテストは、品質担保が粗くなる。この側面について、例を用いて説明する。

例:ECサイトのAPIテスト

例えばECサイトに割引や商品種別、決済方法の機能があるとする。
このとき、購入APIで、割引の全パターンや、商品種別の全パターン、決済方法の全パターンなど、それらの掛け合わせを網羅的にテストすれば、たった1つのAPIに対してパターンの掛け算で1000ケースのテストが必要になるかもしれない。
ただでさえメンテナンスコストがかかり、実行時間も遅いAPIテストで、これだけのケース量を維持することは現実的ではない。
一方で、これを間引いて1〜10ケース程度に絞った場合、個別の割引や決済方法のロジック単体、加えてそれらの組み合わせが、正しく動くのか自信を持てなくなる。

ソリューション

この問題を解決するのが、テストピラミッドという自動テスト戦略である。
  • より粒度の小さいテストで内部品質を高め、品質の大部分をカバーする
  • より粒度の大きいテストは減らす
図を見ると理解しやすいかと思う。

例:ECサイトのAPIテスト テストピラミッド版

実際に、先程のECサイトの例でシミュレーションしてみたい。
テストピラミッドは、より小さい粒度のテストに注力することを推奨する。したがって、上記のECサイト割引や商品種別などの個別ロジックや、それらの組み合わせに対処するロジックなどは、ユニットテストで細かくテストする。
これらはクラスやモジュール単体でテストするため、掛け合わせではなく足し算になる(100ケース以内で足りるかもしれない)。 加えて、より粒度の小さいユニットテストは、作成も低コストで実行も速い。
もちろん、クラスやモジュール単体で動作するからといって、APIとして機能するとは限らず、APIテストは必要である。しかし、大部分の品質をユニットテストでカバーできているため、品質を犠牲にすることなくAPIテストを主要なパターンに間引くことができる。
このようにして、品質と、それ以外のすべて(開発コスト・生産性・実行時間など)を両立することができる。比較イメージを図示する。
なお、テストピラミッドの考え方は、Webサービス単体とシステム全体の関係性においても機能する。
つまり、以下のようなことである。
  • 全てのWebサービスをつなぎ合わせてE2Eテストを1000ケース行うより、E2Eテスト10ケースと、各WebサービスでAPI / UIテスト100ケースずつ行う
    • もちろん、各Webサービス内では、API / UIテスト100ケースをさらに削り、ユニットテストで品質の大部分をカバーすべきである

まとめ

上記説明踏まえ、テストピラミッドの方針をもう一度理解してほしい。
  • より大きな粒度のテストは、控えめにしておく。
  • 心の拠り所として、より小さな粒度のテストに注力する。
テストピラミッドにより、開発コストや生産性、実行時間と、品質の両立が可能となる。 テストピラミッドを無視すれば、品質を犠牲にするか、開発コストや生産性を犠牲にするかのどちらかになる。
特に、ビジネスサイドのメンバはE2EテストやUIテストを重視しがちである。 そのため、テスト自動化を始める際には、まずチームでテストピラミッドを鉄の掟とする旨を合意するとよいだろう。

追伸

本当はAPIテスト自動化のパターンとコツをまとめたかったのですが、テストピラミッドという前提がないと理解が難しいので、先に投稿してみました。
テストピラミッドは、おそらくテスト自動化を始めるときに考えないといけないルールや基準の中でも、最上位に位置するものだと思います。
この大方針の下で、プロダクトの特性を踏まえて、テストの種類の定義(APIテスト、UIテスト等)やサービスの分割方法、各種テストの方式などが決まってくるのだと思います。
需要がありそうだったら、別の記事で、実際にプロジェクトで定めたテスト戦略を事例として紹介しようと思います。

Discussion

コメントにはログインが必要です。