はじめに
本記事は https://event.shoeisha.jp/cza/agile-testing を受講したことで学んだことをまとめたものです。
機能テストあるある
以下のような経験は無いだろうか。
- どのようにテストを設計すればいいかわからない
- テストレビューでテストの網羅性が足りないと言われる
- 優先度の低い機能に対して、重箱の隅をつつくような試験を要求される
- モジュール結合時にモジュール間で仕様が食い違い、開発フェーズに戻る
- リリース後に不具合がよく検出される
これに対して、もっと網羅性を高かめろとか、複数人で確認しながら試験しろとか具体性のない対策を求められることはよくある。
だが、こんな方法論の「ほ」の字もないような対策で良いのか?
確実性の無い対策をしたところで人と金の無駄であるので、ここらで一度テストとは何ぞやを考えてみたい。
テストとは、品質とは何なのか?
そもそもテストとは品質を高めるためのものである。
では、品質とは何なのか。 バグの量? レスポンス速度? 綺麗なUI?
バグが少なくてもレスポンスが遅ければお客様は遅くてイライラすると言うだろう。
レスポンスが速くてもUIがわかりにくければ、お客様は理解できないと言うだろう。
UIが綺麗でもバグが多ければ、お客様は使い物にならないと言うだろう、
どれか一つが良ければいいというものではなく、どれも欠けてはいけないものである。
しかし、全てが完璧である必要は無い。
バグがあっても主要機能に関係ない部分であれば、お客様は特に何も言わないだろう。
一部ページで大容量データを読み込むためレスポンスが遅くなっても、理由があればお客様は納得してくれるだろう。
UIが古いデザインだとしても機能が絞られていれば、お客様は簡単で使いやすいと言うだろう。
すなわち、品質とは具体的なものではなくUXの高さと言える。
品質を高めるためのテストとは何なのか?
UIデザインは別として、バグやレスポンスといった機能・性能面はテスト次第で品質を上げることは可能だ。
では、品質すなわちUXを高めるためのテストとは、一体どのようなものなのか。
あまり使われない機能を100%テストする→NG
あまり使われない機能をテストしたところでUXが高くなるとは考えにくい。
また、工数が増えることで他の機能のテストが疎かになる可能性も考えられる。
凄く使われる機能を80%テストする→NG
残りの20%に致命的なバグがあった場合はUXは一気に低下する。
お客様から非難轟々、緊急メンテナンスが入って結果的に工数が増えることは想像に難くない。
よく使われる機能はほぼ100%、あまり使われない機能は50%テストする→OK
要するに 「何をどのように試験するか」 が重要である。
コア機能はCritical User Journey(CUJ)から重箱の隅をつつくようなケースもしっかりと試験し、あまり使われないような機能はCUJだけで済ましてしまうように、優先順位と取捨選択が求められる。
では、これをどの段階で設計すればいいのか。
開発完了後はシフトレフトではないので論外として、開発中でも少し遅い段階である。
コーディングしてからテストを考えるという時点で、機能ベースなテスト設計を行ってしまい取っ散らかった試験になってしまうからである。
機能ベースな試験と目的ベースな試験
機能ベースな試験と対になるのは、目的ベースの試験である。
これらの違いを以下のようなプログラムを仮定して説明していく。
(引用元: http://www.aster.or.jp/business/contest/doc/2020_U-30_V1.0.0.pdf)
- 3つの整数が入力される
- 各整数は三角形の3辺の長さを示す
- 三角形が不等辺、二等辺、正三角形のどれかを出力する
機能ベースな試験
コーディングした後に、それぞれの関数の分岐を網羅しようとした試験を書くと、以下のようになりがちである。
- 有効な不等辺三角形
- 有効な正三角形
- 有効な二等辺三角形
- 有効な二等辺三角形の際の三種類の辺の組合せ
- 一つの辺がゼロ
- 一つの辺が負の値
- 二辺の和がもう一辺と等しい
- 二辺の和がもう一辺と等しい際の三種類の辺の組合せ
- 二辺の和がもう一辺より小さい
- 二辺の和がもう一辺より小さい際の三種類の辺の組合せ
- 三辺がゼロ
- 整数でない辺
- 辺の数が三つ以外
- 各ケースに期待結果を示している
この試験の書き方で、「十分試験できている!」と自信を持って言える人はおそらくいないだろう。
機能(関数)ベースに書いてしまうと、このようにテストケースに漏れが無いかわからない試験仕様書を作ることになる。
予期しない不具合がリリース後に見つかったり、後任者が「何のために試験しているのかよくわからない」と不満を垂れ流したりするのは目に見えている。
では、目的ベースな試験とはどのようなものだろうか。
目的ベースな試験
目的ベースな試験とは、以下のような試験である。
- 三角形の形に関するテスト
- 三角形が成立する場合のテスト
- 有効な不等辺三角形
- 有効な二等辺三角形
- 有効な正三角形
- 三角形が成立しない場合のテスト
- 直線になってしまう場合
- 二辺の和がもう一辺が同じ
- 面を構成できない場合
- 二辺の和がもう一辺より短い
- 長さが0の辺がある
- 直線になってしまう場合
- 三角形が成立する場合のテスト
- 辺の組合せに関するテスト
- 三種類の辺の組合せ
- 入力の仕様に関するテスト
- 整数でない辺
- 辺の数が三つ以外
- 期待結果を示してあるかどうか
何を試験したいか(テストの目的)を元に、その目的を達成するためのケースを下に書いている。
こうすることでテストケースが十分であるかがわかりやすいだけでなく、追加開発が入った時などに簡単にテストケースを差し込むことが可能である。
また、最も重要なこととして目的ベースな試験はコードを必要としない、つまり要件定義の時点で試験設計が可能である。
これにより、要件定義の段階で仕様やデータフローなどの設計を試験することができる。
これがテストをシフトレフトするということである。
目的ベースな試験の作り方
目的ベースな試験を設計するにはどのようにすればいいのかだが、コードが無いため分析するべき対象がない。
そのため、仕様から連想ゲームで考えていくことになる。今回はマインドマップを使う方法を以下に示す。
対象とするのは、上記で述べた三角形の判定プログラムである。
1. 仕様から考えられることをとにかく書き出す
再度おさらいだが、仕様は以下の通り。
- 3つの整数が入力される
- 各整数は三角形の3辺の長さを示す
- 三角形が不等辺、二等辺、正三角形のどれかを出力する
これらの仕様から考えられることを書きだすと以下のようになる。
一人で行ったので漏れがあるかもしれないが、複数人で行うと漏れも少なくなる。
慣れないうちは複数人で行うことを勧める。
これを使って次にマインドマップを作る。
2. 書き出したことをグルーピングしてマインドマップを作成する
書き出した項目をグルーピングしてマインドマップを作成する。
作成したものが以下となる。
グループ共通項は本当に何でもいい。入力を入力数と入力内容でグルーピングしているが、正常入力と異常入力でグルーピングするのもありだろう。
また、「三角形にならない場合はある?」が入力と三角形の判別の両方にあるが、一つの要素が複数のグループに存在しても問題ない。
それが、複数のテスト観点で影響しうるためであり、どちらで実装および試験するべきかの議論につながるためである。
この状態では、疑問符がついていてはっきりしていない部分があるので、ここから仕様を固めてテスト観点を枝にしたマインドマップを作る。
3. テスト観点を枝にしたマインドマップを作成する。
マインドマップの真ん中には、テスト対象のプログラムもしくはモジュール名を置いてマインドマップを作る。
この時に重要なのは真ん中から1つ目の深さの枝には必ずテスト観点(目的)を置くことである。
小数を許可するようになるなど変更が入った場合に、変更する項目が葉の部分(テストケース)になるため変更が容易となるためである。
また、四角形の判定プログラムを作るとなった場合にテスト観点が似たようなものになるため、このマインドマップを使い回すこともできる。
あとは、これをテスト仕様書に起こせば、テストの目的がわかりやすく後任者も納得しながらテストができるようになる。
そして、ここまでで気づいた人もいるかもしれないが、コードを一切書いていない。
テストはコードが無くても設計できるし、設計によって仕様を試験しているとも言える。
まとめ
テストは仕様の段階で行えるものであるように、シフトレフトとはコーディングよりさらに前の段階まで行うものである。
テスト項目に漏れがあるプロダクトでは、このテスト分析をぜひ使ってみて欲しい。
また、筆者は実を言うと運用・保守担当であり、開発に関してはからっきしである。
もっと詳しく正確に学びたい場合は、本記事の一番上にあるURL先の講座を受講することをおすすめする、