What Is Software Testing? And Why Is It So Hard?
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.111.9188&rep=rep1&type=pdf
#ソフトウェアテスティング #文献
感想 nobuoka.icon
2000 年の文献なので古い部分もあるが、全体的に良い内容だった
この時代からテストは基本的に自動化せよ、って書かれてて、意外と 20 年前からそういうことは言われていたのだなぁ、と思った
内容
ユーザーから報告のあったバグでフラストレーションを感じる経験をすべての開発者がしている
どのようにしてそれらのバグはテストから逃れられたのか? (何百、何千もの変数やコード文を慎重にテストするために、何時間もの時間が費やされたのに)
それを考えるには 2 つを考える必要
開発のコンテキストの中でのソフトウェアテストを詳しく見る必要
ソフトウェアテスターと開発者の役割の理解が必要
次の可能性
ユーザーがテストされていないコードを実行した : 時間的な制約のため、テストせずにリリースされたコードが実行された
実行時の順序の問題 : テスト時とは異なる順序で実行された
テストされていない入力の組み合わせた使用された
テストされていない操作環境
本記事は、ソフトウェアテストの問題とプロセスの概要を通して、テスターが直面する問題を調査し、解決しなければならない技術的な問題点を明らかにする
実際に使用されている解決策についても調査
Testers and the Testing Process
テストを計画して実行するためには、ソフトウェアとその処理、入力とその組み合わせ、そしてソフトウェアが動作する環境を考慮する必要
技術的な洗練と適切な計画が必要 : 優れた開発スキルだけでなく、形式言語、グラフ理論、アルゴリズムの知識
ソフトウェアテストの困難をより理解するため、テストを 4 つの段階に分けてアプローチすることができる
Modeling the software’s environment
Selecting test scenarios
Running and evaluating test scenarios
Measuring testing progress
Phase 1: Modeling the Software’s Environment
テスターの仕事はソフトウェアと環境の間の相互作用をシミュレートすること
ソフトウェアシステムが使用するインターフェイスを特定してシミュレートし、各インターフェイスの入力をシミュレートしなければならない
これは、テスターが直面する最も基本的な問題
様々なインターフェイスがあることを考慮すると、困難な場合がある
4 つの基本となるインターフェイス
ヒューマンインターフェイス : GUI など
ソフトウェアインターフェイス (API) : OS とのやり取りやライブラリとのやり取りなど
テスターとしての課題は、予期せぬサービス (例えば OS 経由でディスクに保存する場合にディスクがいっぱいになった場合のエラー通知など)
ファイルシステムインターフェイス :
ソフトウェアインターフェイスとは別なんじゃろか? nobuoka.icon
通信インターフェイス (物理デバイスへの直接アクセス)
通信プロトコルが必要
テスターは有効なプロトコル・ストリームと無効なプロトコル・ストリームの両方を生成
テスターは、コマンドとデータのさまざまな組み合わせを適切なパケット形式で組み立て、テスト対象のソフトウェアに送信
次に、テスト対象のソフトウェアの外でのユーザーインタラクションを理解する必要がある
例
ユーザーが OS の機能で別のユーザーが開いているファイルを削除する場合
あるデバイスが通信のストリームの途中で再起動してしまった場合
テストすべきユーザーインタラクションの数がかなり多くなりうる
考慮事項
インターフェイスが大きく複雑な場合の 2 つの困難
どのような変数の入力に対しても慎重に値を選択しなければならないこと
入力をどのようにして並べるかを決定しなければならないこと
より複雑なのは同時に複数の値の選択の仕方での挙動の変化
テスターはプロダクト全体にまたがる値の組み合わせを検討する必要がある
入力の順序をどう決定するかの問題もある
物理的な入力と抽象的なイベントを形式言語で表現してモデル化する
一般的なモデルはグラフや状態遷移図だが、いろいろある
他には正規表現や言語理論のツールなど
正規表現での表現の例 : Filemenu.Open filename* (ClickOpen | ClickCancel)
Phase 2: Selecting Test Scenarios
多くのドメインモデルと多数の変数があることから、テストシナリオは無限にも存在するが、そこからどう現実的なテストシナリオを選ぶか?
カバレッジがテスターにとっての最低限の基準
コードカバレッジ : 全てのコードの文を最低 1 回は通ること
入力のカバレッジ : 外部で生成されるイベントを全て適応する
とはいえ、カバレッジ基準を満たしていても、コードの実行順やイベントの発生順などによってバグが起こることもある
それらの組み合わせはやはり無限にある
→ テスターは、無限の組み合わせを分類して、最善のテストデータ妥当性基準 (test data adequacy criteria) に適合するものを選ぶ
「最善」 や 「妥当」 というのは主観的 → 多くの場合、「より多くのバグを発見できるもの」 を探す
実行パステスト基準 (Execution path test criteria)
実行パスについての一般的な選択基準は制御構造のカバレッジ
命令網羅 (全ての文 (statement) を一度は実行する)
分岐網羅 (eachbranching structure (If, Case, While, andso on) to be evaluated with each of itspossible values)
制御フローだけでなく、データフローから考える判定基準もある
各データ構造が初期化され、使われるように、など
fault seeding : 研究者から注目を集めている興味深い方法
ソースコード中に意図的にエラーを埋め込み、そのエラーを見つけるようなテストシナリオを選ぶ → 結果として他のエラーも見つかる
入力ドメインテスト基準 (Input domain test criteria)
単純な外部イベントの網羅で選ぶ方法もあれば、一連のイベントが統計的に無限の入力ドメインを満足するまでランダムに選ぶ方法もある
Phase 3: Running and Evaluating Test Scenarios
テストシナリオができたら、それを実行可能な形式 (多くの場合はコード) にする
なぜなら、手動テストは労働集約型であり、誤りやすいから
可能な限り、テスターはテストを自動化する
完全なる自動化には、各入力源と出力先のシミュレートが必要
テスターは、しばしばデータ収集用のコードをシミュレートされた環境に仕込む (テスト実行中に、有益な情報を出力してくれる)
テストの評価は難しい
実際の出力と期待される出力の比較が難しいものがある
評価のための 2 つの手法
formalism : 仕様の形式化に多大な労力を割き、その仕様から設計とコードを生成する
形式的ではなくても、仕様があることはすごく有益である
embedded test code
2 種類ある
判定しやすい内部データや状態を出力するもの
同じ問題を解く異なる解を 2 個実装し、片方がもう一方を検査する
テスト後、修正が必要な場合は新しいバージョンのソフトウェアが開発される
それに対して、リグレッションテストは必要
修正が失敗している可能性、および、変更すべきでない箇所が変更されている可能性があるため
ただし、これまでの全てのテストを実行するのはコストがかかるため、開発者と連携して最小限のテストにとどめる
また、リグレッションテストでは、テストシナリオ選択フェーズでのテストデータ妥当性基準を無視することにもなる]
関連事項
理想的には開発者はテストのことを考えてコードを書くべきで、検査と確認が難しいようであればコードを書きなおすべきである
テスト方法論についても、自動化と神託問題 (テスト結果の確認が人手でないとできない問題) にどの程度寄与するかで判断すべき
不具合発見時のデバッグに関する開発者との協働
テスターが不具合を特定して開発者が診断するときに出てくる課題 : 不具合の再現とテストシナリオの再実行
不具合の再現は一見簡単なようだが、実際にはソフトウェアや環境の状態を把握しておく必要があって、難しい
Phase 4: Measuring TestingProgress
テスターはテスト進捗をよく聞かれるが、答えるのは難しい
成功したテストシナリオ数やカバレッジ、発見した不具合数などは数えているが、それらをどう解釈するかが難しい (発見した不具合数が多いことは、ほとんどの不具合を発見したことを意味するかもしれないし、ソフトウェアが多くの不具合を抱えていて、まだ不具合が多く残っていることを意味するかもしれない)
多くのテスターは、構造的および機能的テストの完了度 (completeness) によって、上記データを補強する
構造的な完了度の確認の例 :
一般的なプログラミングエラーのテストを完了したか?
全てのソースコードを実行したか?
全ての内部データを初期化して使用したか?
全ての埋め込んだエラーを発見したか?
機能的な完了度の確認の例 :
ソフトウェアが失敗しうる手順を考えて、それが起こらないことを確認できるテストを選択したか?
全ての入力を適用したか?
ソフトウェアの全ての状態空間を探索したか?
ユーザーが実行することを想定したシナリオをすべて実行したか?
テストを完了してよいか、あるいは製品がリリース可能かどうかを判断するのはより難しい
ソフトウェアに残っているバグの数と、それらが現場で発生しうる可能性を、定量的に測定したい
→ 構造的にも機能的にもアプローチ可能
構造的なアプローチ : テスト可能性 (Testability)
Jeffrey Voas により提唱
コード行数がテストの難しさを決めるという考え方は時代遅れ
テスト可能性が高いソフトウェアであれば、テストを監視して、一定のテストを完了した後にバグの発見数が少ないならば、残っているバグも少ないと言える
逆にテスト可能性が低いソフトウェアであれば、残りのバグが少ないというためにより多くのテストが必要
機能的なアプローチ : 信頼性モデル (Reliability models)
過去のデータに基づいて将来の故障パターンを事前に予測しようとする、テストシナリオと故障データの数学的モデルが確立されている
テスト中にソフトウェアがどのように振る舞ったかに基づいて、現場でどのように振る舞うかを予測する
おわり
ソフトウェア会社は製品のテストにおいて深刻な課題に直面しており、ソフトウェアがより複雑になるにつれ、これらの課題はますます大きくなっている
筆者のアドバイス :
見つけることができる最も賢い人々を雇う
彼らが自分の技術を学ぶために必要なツールやトレーニングを取得するのを助ける
彼らがソフトウェアの品質についてあなたに言うときに耳を傾ける
彼らを無視することは、これまでに犯した中で最もコストのかかる間違いかもしれない