ユニットテストで使うテスト技法まとめてみた
はじめに
こんにちは。テスト自動化おじさんのいしいです。
ユニット(単体)テスト、やろうと思ったはいいものの、分らないこといっぱいあって途方に暮れちゃいますよね。
どんなツール(テストフレームワーク)をどう使えばいいのか
テスタブルなコードの書き方って何なのか
どうすれば抜け漏れなくできるのか
どうすれば効率的に実施できるのか
ちょっと調べてみたところ、ツールやコードの書き方はそれなりに記事がありますが、効率的に抜け漏れなくテストを行うためのテスト技法を、ユニットテストにフォーカスして書いてある記事はあんまりありませんでした。(見落としてなければ)
ということで、今回はユニットテストで使うテスト技法を目的別に整理してみました。
なお、JSTQBではテスト技法をブラックボックステスト、ホワイトボックステスト、経験ベースのテストの3分類に大別していますが、今回はちょと違う分類の仕方をしてみたいと思います。
というのも、ブラックボックス、ホワイトボックスという考え方が普及しすぎていて、ユニットテスト= ホワイトボックステストという印象が先行しすぎているように感じるからです。
※多少の異論はあるかもしれませんが、そこは大目に見ていただけると嬉しいです。
また、本記事の目的はテスト技法を俯瞰して整理することであり、各テスト技法の詳細な解説は目的にしていません。
キーワードはちりばめますので、是非知らない技法についてはグーグル先生にご相談になってみてください。
目的別テスト技法
テストケースを適切に削減するための技法
同値分割・境界値分析
説明不要のある意味キング・オブ・テスト技法ですね。テストの入出力のうち、入力にフォーカスした技法です。厳密にいうと削減するための技法は同値分割であり、境界値分析は同値分割したものから、より効率的に不具合を見つける技法になりますが、あえて分けて記載してもややこしいので一括りにして記載しました。
ドメイン分析
聞きなじみがないかもしれませんが、そんなに難しい概念ではありません。
同値分割・境界値分析は1つのパラメータ(変数とか、因子・水準で言うところの因子とも)を対象にした技法です。
一方で、ドメイン分析は2つ以上の相互に影響し合うパラメータを対象にした場合の、同値分割・境界値分析技法です。数学で連立方程式(連立不等式)を解くとx軸とy軸で出来たグラフに線が引かれてxとyの取りうる値が導出されますよね。あのイメージです。
調べるときは不等号(≦,≧,>,<)、ON,OFF,IN(OFFの扱いがキモ)、ドメインテストマトリクスなどのキーワードを理解できると良いでしょう。
2因子間網羅
こちらも入力値となるパラメータが複数ある時のテストケース削減技法です。欠陥の9割は2因子間でみつかるから、複数因子(パラメータ)あっても、2因子間の組み合わせが網羅されてれば大丈夫だよ!…という経験則に基づいた技法です。
こちらはドメイン分析と違って、それぞれの因子が相互に影響し合うとかは無いので、理解に難しいところはありません。代表的なものとして直交表とAll-Pairs法(Pairwise法)があり、それぞれ、以下のような特徴があります。
直交表:水準の出現回数が最大限均等になる。既にある直交表を用いて使うので、因子や水準の数によってはジャストフィットしない可能性がある。
All-Pairs法(Pairwise法):水準の出現回数の均等性は気にせず、最小の組み合わせを提供する。水準の数が1,2番目に多いものを掛け算すれば組み合わせ数がすぐに出るので、とっつきやすい。
入出力の組み合わせを明確にするための技法
デシジョンテーブル
これも大変よくつかわれるテスト技法ですね。
入力が複数あると、出力が複雑になりがちなので、それらの組み合わせがどうなっているのか分かりやすく示すための技法です。
ドメイン分析、2因子間網羅、デシジョンテーブルと見てきてお分かりになると思いますが、入力(ユニットテストで言うところのメソッドの引数)の数が多くなるとテストケースは肥大しますし、それを整理するために色々なテスト技法を活用しなければいけなくなります。
当たり前といえば当たり前ですが、こうしてテスト技法をあらためて俯瞰してみると、ユニットテストにおいて、メソッドの引数をなるべくシンプルにすることが、いかに大事かがよく分かりますね。
作りたいと思ったものが作れているか確認するための技法
制御フロー
C0(命令網羅)とかC1(分岐網羅)とかで表現される、ホワイトボックスなザ・ユニットテストですね。
考え方としては説明の必要もないくらいにシンプルかつ、良く知られたものですが、実はカバレッジ率100%を目指してはいけないのが難しいところ。
シンプルに、工数が大変なことになりますし、過剰なテストの作りこみがリファクタリングの妨げになることもありえます。
「ブラックボックス系のテストを実施して、それでも制御フローのカバレッジを満たせないのは何故か?」
を考える機会を与えてくれるのが制御フローの価値であり、100%埋めることを目的にするための技法ではない、ということには十分注意しましょう。
適切な箇所を適切なカバレッジで検証できるか、プロダクトとアーキテクチャへの愛(理解)が試されますね。
※あわせて、サイクロマティック複雑度などの指標も意識できると良いですね
データフロー
プログラムの処理の中で変数の生成→使用→消滅というライフサイクルが適切に行われているかに着目した技法…ですが、こちらもがっちりテストケースを作ろうと思うとメンテするのは結構大変。
IDE(プラグイン)の機能でデータフロー分析が提供されていたりするので、
そういう機能を上手に活用して、確認すると良いのではないかと思います。
テストケースを適切に増やすための技法(見落としを見つける)
減らす技法があるなら増やす技法もあるのでは?と思われる方もいるかもしれないので、見出しを用意してみました。
実際、増やす技法(という言い方が適切かは微妙なところがあるかもしれないが)はあります。状態遷移図・状態遷移表やユースケースによるテストが、増やす技法といえるのではないかと思います。
しかしながら基本的にユニットテストのテスト技法としてはこれらは使いません。JSTQBの教科書によると状態遷移図・状態遷移表は全てのテストレベルで使えるよ!と書いてはあるものの、実際やろうと思うと、ユニットテストレベルで状態遷移図を用意して考えるのは負荷が重すぎて現実的ではないように思えます。
経験ベースのテストも適切に増やすための技法と言えそうです。
が、これはほかの技法と組み合わせて使うものである&テスト設計者の知識・経験に依存するので今回は記述を割愛したいと思います。
おわりに
ふたを開けてみれば、ブラックボックステストの分類に中分類を足しただけみたいなまとめになってしまいましたが、「たしかにこうやって見てみるとユニットテスト、普通にブラックボックステストの考え方使うな」と思えたのではないでしょうか。(そうでもなかったらごめんなさい)
これを機に、ユニットテストを書くとき、いきなり分岐に注目するのではなく、まずは入出力(メソッドの引数と戻り値)に着目したテストを実装してみてもらえるとたいへん嬉しく思います。
ここまでお読みいただきありがとうございました。
_________________________________
お問合せはお気軽に
https://service.shiftinc.jp/contact/
SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/
SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/
SHIFTの導入事例
https://service.shiftinc.jp/case/
お役立ち資料はこちら
https://service.shiftinc.jp/resources/
SHIFTの採用情報はこちら
https://recruit.shiftinc.jp/career/