EurekaMoments

This is my studying logs about Autonomous driving, Machine learning technologies and etc.

ソフトウェアテスト技法の基礎知識と各技法に対する印象まとめ

目次

背景・目的

ソフトウェアのテストスキルをこれから身に付けようとするときに、
まず最初に悩むのは、「どんなテストをすればいいか?」や「どこ
まで真面目にテストすべきか?」などだと思います。
こういった事に精通している人が身近にいないので、こちらの書籍を
読んで勉強してみました。

はじめて学ぶソフトウェアのテスト技法

はじめて学ぶソフトウェアのテスト技法

今回の記事は、この書籍を読んだ感想と参考になった部分のメモになります。

テストのプロセス

メモ

  • テストの成熟度は5つのレベルに分けられる。
  • レベル0: テストとデバッグにはなんの差もない。
  • レベル1: ソフトウェアが動く事を示すことである。
  • レベル2: ソフトウェアが動かない事を示す事である。
  • レベル3: 発生し得る危険性をある許容範囲まで減らす事である。
  • レベル4: 大袈裟なテストをする事無く高品質なソフトを作るための規律である。
  • ちゃんと設計されたテストケースは、入力、出力、実行の順番の3つで構成される。
  • プログラミング言語によって単体の定義は異なる。
  • C++やJavaでの単体はクラス、C言語での単体は関数である。

感想

自分らが作ったソフトをテストするにあたり、まずは単体テストをする習慣を
身に付けようとしていました。そんな時に迷うのは、どこまで細かくやれば単体
テストと言えるのか、という単体という言葉の定義です。
この章にて述べられているように、単体の定義はプログラミング言語によって
異なる、というのを見て、自分が扱う言語の特性をまずは理解しておかないと
いけないのだなと感じました。

同値クラステスト

メモ

  • 十分なカバレッジを保ちながら、テストケースを管理可能な程度に減らす技法。
  • どの値を選んでも、範囲内の他の値と同じ程度に有効。
  • モジュールで同等に処理されるデータ、同じ結果を返すデータの集合を意味する。
  • テストされる同値クラスを定義する仕様書がある事が前提。
  • モジュールとは、オブジェクト指向でいうメソッドの事。
  • 契約による設計: 事後条件という約束と、それを満たすための事前条件。
  • 防御的設計: モジュールはどんな入力でも受け付ける。

感想

慣れないうちは、あれもこれも徹底的にテストする必要があると考えてしまいます。
ただし、そんなに大量のテストをするのは現実的ではないので、テストケースを
出来るだけ減らせるように入力を決めるのが、テスト設計の基本です。
また、契約による設計や防御的設計について触れている事からして、前段階のソフト
設計が、テストの効率化を大きく左右するのだろうと感じました。

境界値テスト

メモ

  • まず同値クラスを見つけ、次に同値クラスの境界を見つける。
  • そして、各境界について、境界上、すぐ下、すぐ上の値を1点ずつ選ぶ。
  • 「すぐ」がどれくらいかは、データの単位に依存する。
  • 複数の入力フィールドを同時にテストするテストケースを作成する。

感想

if ~ else ~文で条件分岐させる時に、その条件をある変数の不等式にするのは
よくあることだと思います。この実装を汚いコーディングで済ませたり、
あまりに細かく分けすぎると、上記のような境界値テストがやりにくくなりそう
です。条件分岐を実装する際は、出来るだけその分岐を少なくして、後の
境界値テストを効率化する事を意識したいですね。

デシジョンテーブルテスト

メモ

  • システムが満たすべき複雑なビジネスルールを記録するために用いる。
  • 各ルールは、条件の一意な組み合わせを定義する。
  • 各ルールに関連付けられたアクションを記載する。
  • 条件の組み合わせが漏れていないか確かめるのを忘れない。
ルール1 ルール2 ルール3 ルール4
条件
既婚か? Yes Yes No No
優秀な学生か? Yes No Yes No
アクション
割引(ドル) 60 25 50 0
  • 各ルールに対して、テストケースを少なくとも一つ作成する必要がある。

感想

このようなテーブル形式でまとめる事で、条件の組み合わせパターンが
確認しやすくなりますね。このテーブルと、具体的なテストケースが記載
されたドキュメントを紐づけておけば、テストの管理やメンテナンスが
しやすくなって更に良いなと思いました。

ペア構成テスト

メモ

  • どの状況にも、テストすべき多くの組み合わせが存在する場合に用いる。
  • 全ての組み合わせのテストを実行する事は困難。
  • リソースの制約に見合った数のテストケースにまで削減する事を考える。
  • 変数値の全てのペアをテストする。
  • 1~20%のテストケースを作成・実行して全欠陥の70~85%を検出できる。
  • 全てのペアを見つけ出す技法には、「直交表」と「全ペアアルゴリズム」がある。
  • 直交表は、例えば下記のような2次元配列になる。(1と2の組み合わせ)
  • 配列から任意の2列を選ぶと、どう選んでも全ペアの組み合わせが表れる。
1 2 3
1 1 1 1
2 1 2 2
3 2 1 2
4 2 2 1
  • 手順1: 変数を識別する。
  • 手順2: 各変数がとりうる値の数を求める。
  • 手順3: 列数が変数の数以上で、取り得る値の数に対応する値が列に含まれる直交表を見つける。
  • 手順4: 直交表にテスト問題を割り付ける。
  • 手順5: テストケースを作成する。

感想

自分の仕事である組み込みソフトウェア開発に当てはめると、
ここで洗い出されるのは、各種コントローラの種類やOS、
インストールされるアプリソフトのバージョンなどになります。
こういうのは場当たり的に洗い出そうとすると抜け漏れといったミスを
起こしやすいので、ソフトの設計段階で並行して実施しておくのが
良いでしょう。ただし、紹介されている直交表を使いこなすには
書き方を各自が覚えなければならないので、チームで身に付けるまでに
時間が掛かりそうだと思いました。
それに対して全ペアアルゴリズムの方は、下記の記事にあるように、
ペアの洗い出しを自動で行ってくれるツールが公開されているので、
こちらを使ってみるのがトライし易そうな気がします。

tosi-tech.net

qiita.com

状態遷移テスト

メモ

  • ある一つの特定のエンティティを扱う、という点に注意する。
  • 複数の異なるエンティティを混在させてはいけない。
  • 状態遷移表で、抜け漏れのない体系的な検討をする。
  • 現在の状態、イベント、アクション、次の状態という4つの列で定義する。
  • 全ての可能な状態遷移の組み合わせを列挙する。
  • クリティカルでリスクの高いシステムをテストするときは、有効でない状態も含めて、全ての状態遷移のペアをテストする事が要求される。
  • 全ての状態を少なくとも1回訪れるような1組のテストケースを作成する。
  • 全てのイベントが少なくとも1回は起動されるような1組のテストケースを作成する。
  • テスト対象の全てのパスが少なくとも1回は実行されるような1組のテストケースを作成する。
  • 全ての遷移を少なくとも1回はテストするような1組のテストケースを作成する。

感想

テスト以前に状態遷移図そのものの描き方について勉強になりました。
状態遷移図に限った話ではなく、UML図を描く際は一つのダイアグラムに
ついつい沢山の情報を盛り込もうとしてしまいがちです。
でもそうしてしまうと、ダイアグラムの中が窮屈になり見づらくなって、
設計の意図が読み手に正しく伝わらなくなってしまいます。自分はこれまでに
試行錯誤しながら描いてきて、自然とこの考えにたどり着きましたが、
やはり間違っていなかったと実感できました。

ドメイン分析テスト

メモ

  • 複数の変数を一緒にテスト可能な場合に、有効かつ効率的なテストケースを特定できる技法。
  • 同値クラステストや境界値テストをn次の多次元に拡張したもの。
  • 境界値が不正確に定義・実装された状況を見つけるのが目的。
  • ドメインテストマトリックスで、ドメイン分析テストケースを文書化する。

感想

システムの規模が大きくなるほど、内部の変数の種類は多くなります。
一つ一つ独立した変数もあれば、どれかがもう一方に依存してたりします。
各変数を個別にテストしようとはしませんが、必要なテストケースを
しっかり洗い出さずにとにかくまとめてテストして、その最終結果だけOK
ならいいや、とこれまでは片付けていました。
ここで紹介されるドメインテストマトリックスによって、複数の変数を
まとめてテストする事を検討できるだけでなく、各ケースをマトリックスで
リストアップできるのは、抜け漏れを防ぐ事ができて便利だと思いました。

ユースケーステスト

メモ

  • システムの機能を最初から最後まで実行できるようなテストケースの設計
  • ユースケースの構成要素について↓
  • スコープ: 企業、システム、サブシステム
  • レベル: 要約、主タスク、サブ機能
  • トリガー: ユースケースを起動するアクション
  • 拡張: 主成功シナリオが多様化する条件および多様化したシナリオの記述
  • バリエーション: メインフローに影響しないが、考慮するべきバリエーション
  • 優先度: 重要さの度合い
  • 応答時間: ユースケースの実行に要する時間
  • 頻度: ユースケースが実行される頻度
  • 主アクターへのチャンネル: 対話型、ファイル、データベースなど
  • 2次アクター: 実行に必要な他のアクター
  • 2時アクターへのチャンネル: 対話型、ファイル、データベースなど
  • 納期: スケジュール情報
  • 懸念事項: 決定を待っている未解決な課題

感想

今まで自分が作成してきたユースケースでは、検討すべき要素が
まだまだ不十分だったと気づけました。特に重要だと感じたのは、
「拡張」や「バリエーション」の2つです。これらで出来るだけ
多くのパターンを想定できれば、それだけバグを見つけやすく
なりソフトの品質を担保しやすくなります。
ユーザは我々開発者達が想定していないような使い方をする事が
良くあります。そういう時にバグは見つかりやすく、それがユーザ
へのリリース後となっては問題となります。必要最低限のシナリオを
考えておけばいいという訳ではなく、柔軟な発想でいろんなシナリオを
テストする癖を日頃からつけようと思いました。

制御フローテスト

メモ

  • 実装されていないパスは見つけられない。
  • フローは正しくても、ステートメントの取り扱いが不正確。
  • 特定の少数のデータの場合は、処理に失敗するかもしれない。
  • ループの実行を制限することで、意義のあるテストケース数の削減が可能になる。
  • 構造化テストの手順①: モジュールから制御フローグラフを作成する。
  • 構造化テストの手順②: グラフのサイクロマチック数を計算する。
  • 構造化テストの手順③: サイクロマッチック数の分だけ基礎パスの組を選ぶ。
  • 構造化テストの手順④: 各基礎パスに対応したテストケースを作る。
  • 構造化テストの手順⑤: 以上のテストを実行する。
  • サイクロマチック数: 独立でループを含まないパスの最小数

感想

各関数に対して単体テストを書くようになった当初、「こんなの
全パターンやってられない」と思い、どうしたらいいのかと困って
いました。この書籍を読んだ事で、テストを有効性を維持した上で
テスト数を削減するやり方を学べたので、非常に参考になりました。
今の職場では単体テストを実行する習慣が元々ないので、そこから
新たに習慣づける事は非常に大変です。各プロジェクトはかなり
厳しいスケジュールで進んでいるので、テストの実行に手間取って
いてはすぐにやらなくなってしまいます。
今回学んだようなテスト数を削減する事と合わせていけば、単体
テストの習慣は浸透させやすくなるので、これからトライして
いこうと思います。

データフローテスト

メモ

  • データ値を持つ変数には、生成、使用、消滅(廃棄)のライフサイクルがある。
  • モジュールの全ての変数に関して、定義、使用、消滅の状態を詳細に示す。
  • 下記のような条件を満たすテストケースを十分な数だけ選択する。
  • 条件①: 全ての「定義」が「使用」に結び付く。
  • 条件②: 全ての「使用」が対応する「定義」から繫がる。
  • モジュールを通過するパスを列挙する。
  • 各変数で、全ての定義ー使用のペアを最低1回は網羅するテストケースを作る。

感想

今まで変数のライフサイクルを意識したテストはした事がありませんでした。
変数が未定義であったり、未使用であったりは、コンパイル時やコードレビュー
時にそれなりにチェックが出来ていたからです。
ただし、モジュール内の処理が複雑になると、その分だけ変数も多く定義する
事になるので、こういう時は似たような名前の変数をついつい複数個定義して
しまい、変数への値の代入を間違えがちです。そういう時こそ、このデータ
フローテストという技法が大事になってくるのかもしれません。

スクリプトテスト

メモ

  • 再現性、客観性、監視性が重要なところで利用される。
  • 再現性: 作成者以外の誰かが実行しても同じ方法で実行できる。
  • 客観性: 作成者のスキルに依存する事なくテストケースを作成できる。
  • 監査性: 要件、設計、コードからテストケースに対するトレーサビリティ。
  • 本物のテストでは、テストの結果は実行前に予想され、文書化されている。
  • システム要件の品質に大きく依存する。
  • 柔軟性に欠ける。興味深い現象を見つけても深くは追跡しない。
  • しばしばテストのスキルを低下させる。

感想

メリットよりもデメリットの内容が気になりました。
「テストのスキルを低下させる」というのは具体的にどういう事なのか、
しばらく考えましたが、「スクリプトによってテストが自動で実行される
ことで、あまり難しい事を考えなくてもテストを誰でも実行できるように
なるが、その代わりにテストを検討・作成するようなスキルが身につかなく
なる」というのが自分の認識です。
どこまでをスキルというのかが曖昧ですが、このテスト技法で難しいのは
スクリプト化するテストのシステムを確立する事と、それを管理する事では
ないでしょうか。個人的にはこれらも立派なテストスキルだと思っているので、
決してスキルを低下するという事ではないと考えています。

探索的テスト

メモ

  • テスト設計とテスト実行の同時並行的な学習行為。
  • 今できることで、一番大切なテストは何かを考える。
  • テストを知的に豊かで柔軟なものにする。
  • リスクを評価し、それをテストの道しるべにする。
  • ささいなことに惑わされない。
  • フィードバックが弱い、遅い、存在しないプロセスはうまく機能しない。
  • 短い時間内に、迅速なフィードバックを求められた場合に役立つ。
  • 欠陥を予防する力は持っていない。
  • スクリプトテストを補完する技法として検討する。

感想

製品について理解を深めながらテストも設計、実行するというのは、
システムの規模があまり大きくなければある程度やれそうですが、
もっと大規模なものに対してはあまり現実的な技法ではないように
感じました。
また、本来であればそんなに短期でフィードバックを求めるような
テスト計画は誰もが立てたくはないはずなので、最後の手段という
印象が強いですね。いい言い方をすれば柔軟、悪い言い方をすれば
場当たり的といった感じでしょうか。