私がいろいろな方から教わったり、勉強したことから考えた 「ちゃんとしたテスト」 について書きます
ちゃんとしたテストについて書かせて頂きます。
色々な意見があると思いますが、ぜひお聞かせください。
皆さんの足元に及ばないかもしれませんが、議論をさせてください。
↓ のつづき、書きます。
私の考える、ちゃんとしたテスト
単機能テスト
勉強して気づきましたが、自分が昔やっていたのは有則の単機能テストでした。
機能が仕様どおり実装されているかを確認していたからです。
なので仕様に定義されていない箇所のテストを考えられているか、以降は注意を払えるようになりました。
テストだけではなく、設計時にも。
テストの目的
仕様通りに実装されていることの確認です。
テスト設計の流れ
テスト対象の論理を把握する
どうテストを設計をするか、つまりテストケースを考えるかについてですが、その前に機能全体を把握している必要があると考えます。
知らない場合は、仕様書から把握するようにします。
ですがその当たり前がないケースも多々あります。
超短納期で設計と実装が並走する、意味がわからない状況もたまにはあります。
辛いですが、そんなときは息抜きを意識して、あきらめないようにしましょう。
これはテスト対象全体を見た時に、その一面だけを捉えてしまうことで、隠された項目や条件を漏らさないようにする為です。
例えば、画面の項目の表示、非表示を制御する設定ファイルの設定値などです。
ですから機能の外側を見て、入力、出力の数を見ます。
それぞれに複数入出力があれば、複数の論理(ロジック、筋道というと分かりやすいかも)があることが分かります。
HAYST 法において利用されるラルフチャートに近いかもしれません。
論理毎にテスト項目を探す
次に、論理一つずつに焦点を当て、その観点で機能の内側を見ていきます。
例えば、商品マスタ登録画面に、登録、削除、更新の機能があるなら、その3つの観点それぞれで見ていきます。
論理を一つづつ見ていくのは、経験的に処理毎に使われる項目が変わるかもしれないからです。
もしかしたら登録した商品コードはキーとして使われる為、更新できないかもしれません。
そうなると、更新時のテスト項目と、登録時の項目とは同じにはなりません。
ですから、私は単機能のテスト設計は論理ごとに行うと良いと考えました。
ところが、中には複雑な論理を1つの画面で実現する処理もあったりします。
そういう時は、テスト技法を活用すると良いです。
便利な技法
上記を支援する技法としては、論理を表現する、原因結果グラフ、CFD があります。
テスト技法としても紹介されるものですが、ここではツールとして紹介します。
私は、シンプルさと定義外の論理が見えてくることからCFDをプログラマさんとのテストケースレビューで使ったりします。
紙にちょろっと書く程度ですが、仕様を知らない場合、初めに論理の認識合わせをしてからでないとテストケースをしても効果がありません。
ですからレビューをするために書くのです。
本当は設計にこれら技法で表現された図があるといいと思っていますが、そうもいかないことが多いですから。
論理のテスト前に、単機能(単項目)のテスト
話を戻します。
論理を書いた後ですが、すぐには仕様としての論理の検証はしません。
なぜなら、その論理を構成する要素(単項目のチェック処理や、分岐条件の導出など)に誤りがあると、論理を作り直し(プログラム修正)になるからです。
プログラムを作り直したらテストはやり直しです。
私の場合は、ユニットテスト(≠単体テスト)を(書いてみたいけど)書いたことがない(書けない)ので、手作業でやり直しになります。
これは辛くて耐えがたい作業なので、ちゃんと単項目のテストをしようと考えました。
これはユニットテストの考え方に通じるものがあります。
アーキテクチャ構成要素の最小単位が検証され、品質が保証されていれば、そのアーキテクチャ構成要所の最小単位で構成される要素も同レベルの品質が保たれる可能性はあります。
この一方でアーキテクチャを構成する要素の中で一番数の多い最小単位の品質が悪いと、品質は一番低いものに足を引っ張られる特徴がありますので、システム全体の品質もその程度になってしまいます。
単機能テストのテスト技法
単機能をテストするときに確認するポイントは大きく2種類あります。
単項目の仕様(書式、値のチェック処理など)
単項目の仕様をテストする場合は、同値分割、境界値分析があります。
単項目の種類(文字、数値、日付、コードなど)に着目して、仕様から同値クラス、境界値を分析するのがポイントです。
また、テストを流す時はテスト対象外の項目はデフォルト値にすることがポイントです。
テストをしたい項目に他の項目の値が作用することを防ぐためです。
複数項目が関連するチェック処理
複数項目チェック処理をテストする場合は、デシジョンテーブルを作り、分岐条件を整理します。
上では原因結果グラフを論理を整理するツールとして紹介しましたが、ここではテスト技法として紹介します。
これを書けるようになるとCEGTestという、私がWACATEを知るきっかけをくれた方が作成してくださったツールが、圧縮済みのデシジョンテーブルを出力くれます。
私はこのことが便利なのは知っているのですが、僕はまだ原因結果グラフを書けないので、出来る範囲でデシジョンテーブルを作って圧縮せずに網羅的に整理してしまっています。
以上が単項目テストの設計手順です。
このように、ちゃんとした単項目テストを考えるようになりました。
皆さんの単機能テストはいかがでしょうか。
組合せテスト
単機能テストでは論理ごとにテストをしてきましたが、論理毎に見てもそれだけでは安心できません。
本来、論理毎に使われる内部的な変数を共有している可能性があるので、組合せテストをする必要があるのです。
テストの目的
論理内、論理間で使われる単項目を組合せた時に、仕様にない組合せで意図しない結果を引き起こさないかを確認することです。
組合せテスト設計技法
HAYST 法による直交表やオールペアがあります。
HAYST 法は実体験したことがないので、ペアワイズとどれだけバグ検出に差が出るのかは何とも言えませんが、テスト項目の導出だけならPairWiseを良く利用します。直交表を作る手順を整理できていないのと、PICTという便利なツールがある為です。
ですが、テスト設計の為には、HAYST 法 で紹介されているFV表、ラルフチャート、FL表の活用が有効だと考えています。
以上、単機能テスト、組合せテストは必ず単体テストのテストレベルで実践します。
組合せテスト2
私は組合せテストの考え方は、複数機能間のテストにおいても利用できると考えています。
余談
いきなり余談ですが、私はテスト設計について以下のような考えを持っています。
- 有効なテストケースを作成するテスト工程の一作業である
- テストケースの作成には、テスト技法、経験的に有効であると認められた知識としてのテストケースを取り入れることが、効率的で効果的なテストケース作成に有効である
私は様々なテスト技法の活用シーンを理解しておけば、「どのテストタイプ、どのテストレベルでどんなテストをしたらいいか」という疑問は少なくなるのではないか考えています。
「◯◯は死んだ」が今話題ですが、人(組織・チーム)を見て、技法(技術)を効果的に適用できるシーンから、適切なインテグレーション(適用、統合)の方法を考えればよいだけのことだと思うのです。
その人にとって見れば◯◯が合っていて、効果があればそれでよいのです。
機能間テストへの組合せテストの応用
ですから、複数機能間のテストでも、複数機能を一つの業務や作業のまとまり(サブシステム、機能よりも大きなまとまり)と考えて、テスト対象の因子をHAYST法で紹介されている6W2Hで分析していくと良いと思います。
例えば、「商品を出荷する」という作業のまとまりは、次の通りの作業で構成されていたとします。
・出荷指示を貰う
・出荷対象を在庫から引当する
・出荷対象をピッキングする
・出荷対象を検品、梱包する
(・出荷対象に宅配便伝票を貼る)
(・出荷対象を運送業者に渡す)
・出荷対象を出荷した記録を残す
※()は人手の作業
「出荷対象を検品、梱包をする」に改修が入った場合、「ピッキングしてきた出荷対象」が正しく検品できるか、が気になります。
また、「検品した出荷対象」に対して、「出荷した記録を残せるか」が気になります。
このように、作業を構成する機能間のインタフェースに不整合が無いことを確認できれば、既に単機能でのテストをしているので、上述した「商品を出荷する」の業務は滞りなく行えることを保証できます。
しかし、「ピッキングの商品リストを出力する作業の前に「商品名称の修正」をしたとしましょう。
普通に(?)設計されていれば、注文受付済みのトランザクションが、マスタを参照するような設計はしないですが、万が一設計か実装に欠陥があったとします。すると、業務担当者が商品名でピッキングしていたら、AでピッキングするはずだったのにBをピッキングすることになってしまいます。
このような一見関係のない機能間の処理によってデータの状態が変わってしまうような欠陥もあります。
組合せテストには、「有則/無則」という考え方があります。(禁則もありますが、理解が浅いので割愛します)
仕様の確認は「有則」のテストです。
仕様にない欠陥の発掘をするのが「無則」のテストです。
よって、無則のテストでは因子の1つにテスト対象の業務を構成する2機能(2水準)、もう一つの因子に水準に無関係な機能をN水準として、無則の組合せを考えます。
テスト対象と無関係な機能とは
これは、テスト対象機能で利用している情報を更新、削除する可能性のある機能と考えると良いです。
テスト対象機能において、SQL でマスタと結合してデータを取得してくることが出来る項目があったら、そのマスタを無関係な機能とすると良いです。
正常系の処理をしていた時は問題なく処理できていても、途中でその取り扱うデータの状態を変える可能性のある処理をしたときに思わぬ影響を及ぼすことがあります。
組合せテストではこのような利用方法がありますので、統合テストのテストレベルでも心がけるようにするようにしています。
状態遷移テスト
機能間の組合せという点では、システムやデータの状態についても、同様のことが考えられます。
状態遷移テストの目的
機能間の組合せテストでは、状態ではなくデータ不整合の有無に着目をしますが、
システムやデータには状態があり、ここで整理する状態遷移テストではそれら状態の正しさを確認します。
状態の特徴
データの状態は様々な処理の条件となる場合が多いです。
例えば、「ネットでの注文を確定するときの条件」です。
ネットでの注文には「品切れ」という商品の状態があります。
商品を選んでいた時は在庫があっても、注文確定時には商品が品切れになっている場合があります。
商品がカートに入っているからといって、品切れの商品を注文できてしまってはクレームに繋がります。
このように状態に着目してテストをするのが状態遷移テストです。
テスト技法
これらは、トリガーと状態の状態遷移表を書くとテストすべき仕様をきれいに整理できます。
また、状態遷移表を元に、遷移前、遷移後の状態の関係行列を作ると有則、無則の状態遷移をチェックできるのでおすすめです。
つまり、状態遷移表では仕様にあまり記述されない無則の部分の見落としを防ぐことが出来ます。
組合せテストと同様に、遷移が無いはずの処理を実行したときに、状態が遷移したりしないか注意することが出来るようになるので、よりバグが潜んでいそうなところをテスト出来ます。
更に、関係行列を2乗した1スイッチカバレッジ表まで作って、全パターンテストをすると内部の変数の故障などが見つかって良いです。
以前この関係のバグを見つけたときの例をツイートしたのですが、忘れてしまったので、思い出したらまた書きたいと思います。
シナリオテスト
シナリオテストも同じように、有則、無則の考え方を取り入れてテストをします。
テストの目的
システムを導入、改修して改善に取り組もうとした当初の目的を達成できているかの確認です。
改善するパターンをシナリオとして、そのシナリオをなぞります。
しかしなぞるだけでは仕様通りになっている事しか確認できません。ここでも有則・無則の考え方を適用します。
- 正常シナリオ
- 準正常シナリオ
- 異常シナリオ
この3点について考えてシナリオに対する考慮の抜け漏れを確認します。
また、シナリオを考えるときはHAYST 法の6W2Hで、考えると良いです。
(先日のリナさんと秋山さんのツイートを見て)ユースケーステストとは違うので要注意です。
シナリオテストはまだそれほどやり方を確立できていないので、この辺にしておきます。
ぜひ皆さんのシナリオテストを教えてください。
チームで一定のテストをすることのむずかしさ
この様に考えても、チームメンバーにその通りに実践してもらうのがなかなか難しいです。そもそも一定のテストをしたのは、テストケースの作成レベルにバラつきが多いからでした。
ですから、私の今の課題は、以上を実践して、メンバーからフィードバックをもらい、改善して、設計結果を全員でレビューしやすいフレームワークにすることです。
ちゃんとテストして嫌な思いをしたくないですから。
チームで一定のテストを実践、フィードバックを貰う為に取り組んだこと
実践してもらうにしてもある程度のフレームワークが必要です。
そこで、私はこの手順をテスト計画書の雛形として書き込みました。
私がいるチームでは作業をお願いする方が頻繁に入れ替わります。
その都度説明をするのは骨が折れます。ですから、計画書にして形式知にすることにしました。
実践したことの評価
しかしこれだけでは定性的な評価のままで、テスト設計の為のフレームワークのエコシステムは成立しません。
計画時に評価指標を定義して、計画時に想定した指標に対してレビュー時に評価しようと考えています。
陳腐化対策
さらに、仕事を一緒にしている人、WACATE のような勉強会で出会った方からの意見を頂いて的外れなことを言っていないか確認したいと思っています。
今日ここに来たのもそのためです。
まとめ
以上が、私が教科書を噛み砕いて、色んな方に教えて頂いて考えた、 今の実践する必要があると思っているちゃんとしたテストです。
もっとたくさんのことを学んできたはずなのですが、自分からアウトプットできないということは勉強したことが定着していない証拠だと思います。
これが私の実力だと真摯に受け止めて、これからは特に実践に励んでいきたいなと思います。
ぜひ皆さんのちゃんとしたテストについてもお聞かせください。
TwitterでもFacebookでも、カフェでもお酒を飲みながらでも、よろこんでお話をお聞きします。