テストケースを変えない工夫

※本稿はソフトウェアテスト Advent Calendar 2020 24日目の記事です。

こんにちは、Magic Podの開発をしている脇坂です。好きなものは単体テストとリファクタリングとテニスです。

さて、今日はリグレッションテスト、機能テストの文脈で話をします。テストケースを変えない工夫というのは、継続的にテストケースを実行する上で必要不可欠なテクニックです。このテクニックは自動テストの文脈で語られることが多いですが、手動テストにおいても応用可能だったりします。


話すこと

  • テストケースを変えるべきではない理由
  • テストケースを変えずに済ませる工夫

話さないこと

  • フレーキーテスト問題に対するシルバーブレッド
  • 非機能要件のテスト

背景

昨今、AgileやScrum、DevOpsが盛り上がりを見せている関係から、自動テストやCI/CDへの関心や要求が高まっています。自動テストのコミュニティが成熟してきているので、自動テストするときはテストオートーメーションピラミッドが素晴らしくて、アイスコーンはダメ、E2Eテストはフレーキーになるから気をつけよう的なことが徐々に一般に知られるようになってきました。

適当なことを言いましたが ここで重要なポイントは、自動テストというのは継続的に運用するものであり、理想の世界においては、常に偽陰性のないテストOKか偽陽性ではないリグレッション※1を検知するかのどちらかであって欲しいということです。※2

テストケースの変更

一度書かれ、テストOKになったテストケースというのは、その後どの程度の変更を想定する必要があるのでしょうか?ここでいうテストケースというのは、自然言語あるいはプログラミング言語で記述された、特定の期待値とそれを確認する手順のことぐらいに思ってください。テストケースをちまちま変えるのは大変ですね。フレーキーテストに対応するために毎日テストケースを変えるのも大変ですね。よって理想の世界における答えは、「テスト対象の振る舞いが変わらない限り、テストケースは変更されるべきではない」というものです。

これを説明するにあたり、開発者がテスト対象に対してどんな改修を行うかを理解する必要があります。開発者が行う改修というのは、基本的に次の4種類に分類されます。

  1. リファクタリング
  2. 新機能追加
  3. 不具合修正
  4. 振る舞いの変更

1. リファクタリング

  • 機能性を変えないメンテナンス作業。テスト対象のコードベースの可読性をあげたり、パフォーマンスを改善したりするために実施される
  • (主に自動)テストケースは既存機能を壊していない事を確認するために存在するのであって、全てテストOKになるべきである。つまりテストケースは変更されるべきではない
  • リファクタリングで(主に自動)テストケースがNGになる時、本当に既存機能を壊しているか、適切な抽象度でテストケースが作られていないかのいずれか(特に単体テスト)

2. 新機能追加

  • 新機能を足す時、既存機能は影響を受けるべきではない
  • 既存の(主に自動)テストケースの結果はすべてOKであるべき。つまりテストケースは変更されるべきではない
  • 新機能追加で(主に自動)テストケースがNGになる時、基本的には既存機能を壊している

3. 不具合修正

  • 不具合修正はテストケース不足から起きる問題。考え方は新機能追加とほとんど同じ
  • テストケースは不足しているので追加する
  • 既存機能は不具合修正から影響を受けるべきではないし、既存の(主に自動)テストケースも変更されるべきではない

4. 振る舞いの変更

  • 振る舞いの変更というのは、稼働済みのシステムが提供する1機能をごっそり変えてしまうこと。言い換えると、後方互換性のない変更のこと※3
  • システムが稼働するというのは契約のようなものであり、ユーザはシステムが提供する機能に依存するものなので、振る舞いの変更するというのは契約を一方的に変えるようなもの。影響が大きい
  • 振る舞いが変更される時、既存のテストケースの期待値を変更する必要がある

まとめると、理想の世界において、リファクタリング、新機能追加および不具合修正の場合は全てテストOKになるべきであり、振る舞い変更の場合のみ、テストケースの期待値が変更される必要があります。

この理想の世界に少しでも近づくために何をすべきでしょうか。どうすればメンテナンスフリーなテストケースに近づくことができるでしょうか。それは「詳細(手段)」には、なるべく立ち入らないことです。

単体テストの場合

単体テストにおける「詳細(手段)」には立ち入らない工夫の1つを紹介します。知ってる方も多いかもしれませんが、それはパブリックAPIを使ってテストするということです※4

これは何故でしょうか。これを説明する鍵は、そもそもパブリックAPIとは何か、というところに帰着しますが、パブリックAPIというのは、ユーザやサードパーティが自由にアクセスできるAPIのことです。先ほど述べたとおりこれは振る舞いの変更が起きない限り、決して変わることのないAPIなので、これらに対して書かれたテストケースというのは理論上安定します。

一方、プライベートAPIは主に次の2つの理由により、比較的簡単に変更されます。

  1. ユーザやサードパーティが使用していない (チーム内のみで使用される)
  2. システムが機能を提供するための手段にすぎない (外部から見た振る舞いではない、実装の詳細と呼ばれたりする)

なので、プライベートAPIは例えばリファクタリングの餌食となりやすく、プライベートAPIに依存するテストケースというのは脆くなります。

Web/Mobile E2Eテストの場合

エンドユーザやサードパーティから見えるパブリックAPIを使ってテストするべきと書きました。これは愚直に捉えるとE2Eテストが好ましいということになります。Web/Mobile E2Eテストの時代なのでしょうか。我々の時代がやってきたのでしょうか。確かに、メンテナンスフリーで継続的に動くWeb/Mobile E2Eテストは最高ですね。本物のユーザと同様の環境・操作で偽陰性/偽陽性なくテストOK/NGを出してくれるそれは、きっとチームに自信を与えることでしょう。

弊社はWeb/Mobile向けのE2Eテスト自動化サービスを開発/運営しているので、Web/Mobile E2Eテストの時代の到来を甲高く叫びたいところではありますが、ちょっと慎重になる必要があります。皆さんご存知のとおり、Web/Mobile E2Eテストの運用というのはフレーキーさとの戦いの連続です。Web/Mobile E2Eテストのフレーキーさについてはこちらの素晴らしいスライドをご覧ください。オンライン発表をリアルタイムで見ていましたが、会場は共感の嵐でした。

この発表の中で「テストケースに書いてないことが起きる」という話がありましたが、その理由の1つに「Webは詳細」というのがあります。

Webは詳細

「Webは詳細」※5とはどういうことかというと、 Webというのは手段であるということです。 Webのサービスがたくさん作られているのは、ほとんどの場合、ユーザビリティが高いからではないでしょうか。今はコロナ禍ですが、そうじゃなくても、専用のハードウェアを買ったり、サービスベンダーのデータセンターに行って目的のサービス使ったりするのは微妙ですね。また、世界に占めるソフトウェアエンジニアの割合は1%にも満たない※6ため、コマンドプロンプトやシェル、ターミナルを使わせるのも現実的ではありません。よって、おうちのパソコンのWebブラウザ上で完結させる方がよっぽどユーザー体験はいいはず。まとめると、Webとはユーザビリティを実現するための手段であるということです(Mobileも同様です)※7

さて、Webは手段です※8。なので、いいか悪いかは別として、同じ目的を果たせるのであれば手段は変わる傾向にあります※9。 なので、例えば、ちょっとレイアウトが気持ち悪いので、ボタンの位置を変えよう、IDを変えようとか起きます。こういう理屈で WebのE2Eテストが壊れることがあります。Mobileも同じですね。

なので、最近ではWebの詳細(e.g. 画面レイアウト)に立ち入らない方法として、Web APIを使ったテストが流行ったりしています。

手動テストの場合

「詳細(手段)」に立ち入らないテクニックは自動テストだけの特権でしょうか?そうではありません。手動テストにおいてもそのテクニックは認知されていて、JSTQBのシラバス にも載ってます。1つは皆さんもよくご存知の探索的テスト、もう1つは具体的/論理的テストケースです。具体的/論理的テストケースの細かい説明はシラバスに譲りますが、これはテストケースの抽象度を調整するテクニックです。論理的テストケースが抽象度の高いテストケースで、具体的テストケースが抽象度の低いテストケースです。これは良し悪しではなくトレードオフの問題です。抽象度を高める分だけ、テスト担当者の創造性が発揮されて、テストケースのメンテナンス性が良くなり、その一方でテストケースの再現性は悪くなります。

メンテナンス性が効いてくるのは、テストケースがリグレッションテストである場合です。リグレッションテストのテストケースはほとんどの場合、なんらかの形でバージョン管理されていることが多く、雑なことを書いていると、あとで痛い目をみます。なので、テスト対象の改修の影響をなるべく受けないように書きあげる技術が必要になります。

Web/Mobile E2Eテスト自動化サービスの場合

我々は少なくともWeb/Mobile E2Eテストがフレーキーになりがちであることを知っています。Web/Mobile E2Eテストは忠実性が高い※10 一方で、それはテスト対象が稼働するために必要な全てに依存して行われるため、必然的にフレーキーになります。Web/Mobileの詳細に立ち入らなければならない我々がしていることの1つに自動修復(セルフヒーリング)があります。

自動修復というのは、テスト対象要素が見つからない場合に、AIがテストを自動修正して処理を継続する機能※11です。なので、例えば「ちょっとレイアウトが気持ち悪いので、ボタンの位置を変えよう、IDを変えよう」といった変更に強くなります。これは、「詳細に立ち入らないことは困難なので、せめて人間の仲介を可能な限り減らそう」という、これまで紹介した話とは考え方の異なるアプローチといえます。

まとめ

テストケースは基本的は変えるべきではなくて、変えないための工夫として「詳細に立ち入らない」テクニックをいくつか紹介しました。テストケースに必要とされる詳細具合(抽象度)というのは、チームの状況やテスト観点によって変わってくるかもしれません。トレードオフだと思います。しかし、適切な詳細具合で記述されたテストケースというのは継続的に実行していく上で有利に働きます。手動であれ自動であれリグレッションテストを運用していくにあたって、考えてみてはいかがでしょうか。

あとがき

「テストケースの変更」と「単体テストの場合」の話はSoftware Engineering at Googleの12章をかなり参考にしました。そこにはGoogleの単体テストに対するアプローチが述べられています。全体的に良書だと思います。

注釈・出典

  1. 102.テスト界隈で使われる言葉『デグレ=リグレッション』
  2. 偽陰性/偽陽性についてはこちら(手前味噌)
  3. 後方互換性について
  4. プライベートメソッドのテストは書かないもの?
  5. この言葉はソフトウェアアーキテクチャ界隈で有名なボブおじさんが書いたClean Architectureという本からもってきました
  6. 世界のIT技術者は推計2137万人、日本は第4位で国内人口の0.86%
  7. 個人的には、Web/Mobile のE2Eテストの半分ぐらいはユーザビリティテストだと思っています。
  8. Web/Mobileを貶める意図はありません。Web/Mobileは最高の発明だと思います。それから、高度なUI/UXを実装するエンジニアを大変尊敬しています。
  9. 私などはそれを「ユーザビリティが悪くなった」と言いつつ、他に代替がないあるいは代替を探すほど困らないという理由で使い続けたりします
  10. 本番同様の環境で、本物のユーザと同様の操作を行うため
  11. より詳しくはこちら

関連記事

この記事のハッシュタグに関連する記事が見つかりませんでした。

最新記事

人気の記事

アーカイブ

タグ