この記事は、インテル® デベロッパー・ゾーンに公開されている「The Right Mindset for Testing (Testing Theory Part 1)」(https://software.intel.com/en-us/blogs/2017/02/06/the-right-mindset-for-testing-part-1) の日本語参考訳です。
この記事の PDF 版はこちらからご利用になれます。
欧州宇宙機構のスキャパレリの火星着陸失敗に関する最近の投稿 (https://software.intel.com/en-us/blogs/2017/01/11/the-schiaparelli-lesson-unusual-and-faulty-conditions) は、テスト、テストツール、および適切なテスト方法について議論されるきっかけとなりました。https://software.intel.com/en-us/meet-the-developers/evangelists/team/jakob-engblom と Wind River* のブログ (http://blogs.windriver.com/simics (英語)) で述べたとおり、明白なもの以外にもテストを拡大し、実際には簡単にテストできないものも (シミュレーションにより) テストすることが繰り返し議論されてきました。テスト理論に関するこのシリーズ (全 2 パート) では、テストに対する私の考えを要約し、いくつかの逸話を皆さんと共有したいと思います。
このシリーズのパート 2 はこちらからご覧になれます。
テスト環境
一般に、コンピューター・システムのソフトウェア (自動車、航空機、ロボット、サーバー、ラップトップ、ロケット、トースター、携帯電話、原子力発電所を含む) は、特定の状況、入力、状態、環境条件下での動作を仮定して設計されています。ソフトウェア・テストは、ソフトウェアが仕様どおりに動作すること、つまり、システムの設計内で想定される適切な入力に対して正しい結果を出力するのを示すことを重視する傾向にあります。
想定される適切な入力とは、コマンドライン・インターフェイスでの有効なコマンド、計算関数に対する適切な値、制御システムで想定される範囲内のセンサーの値、プロトコルで指定された形式のネットワーク・パケット、GUI での適切な順序のクリック操作などを意味します。通常、プログラマーは、ソフトウェアが正しく処理を行い、想定どおりに動作するように、この部分に力を入れます。結局のところ、ソフトウェアが本来のタスクを実行しなければ、意味がないからです。
想定される入力以外は、無効または異常な状態や入力です。ソフトウェアは、そのような状態にも対応する必要があります。そのため、コンパイラーは構文エラーメッセージを出力します。Web フォームの年齢フィールドに “none of your business” や “ABC” などの文字を入力したら、システムはエラーメッセージを出力するでしょう。エラー処理は、ソフトウェア開発において重要です。
異常状態は、2 つに分類することができます: 正しく動作するシステムで異常値が発生した場合、および破損による障害。例えば、航空機が 500km/h 未満で飛行するように制御するシステムの設計では、急降下により航空機が 500km/h になった場合、システムは正しく動作していますが、異常状態と言えます。一方、速度検出システムが破損し、システムの実際の状態と関係のない乱数地値が報告される場合は障害です。
どちらの場合も特異なまたは異常な状況であり、異なる対応が必要になります。異常状態はシステムの実際の状態を示し、それらに適切に対応するためアルゴリズムの拡張が必要です。現実の世界ではさまざまなことが起こります。システムは、それらに対応できなければなりません。一方、障害には、システムの障害を検出可能なパラノイドロジックが必要です。障害が検出された場合、不具合のあるコンポーネントに依存しないフォールバック・プランを使用する必要があります。多くの場合、物理的な冗長化、および 1 つのセンサーで不具合が発生した場合は複数の異なるセンサーを使用することで、障害に対応します。
以下に、ソフトウェア・システムが遭遇する可能性のある状態についての私の考え方と、システムの特定の動作状態に対するエンジニアの典型的な見解を示します。
最も内側の緑色のボックスは、システムの通常状態のセットを表します。想定される入力、適切なプログラム、制御システムの標準動作状態、航空機の設計速度などが含まれます。
黄色のボックスは、想定される状態と障害を表します。これらのケースに安全に対応できるロジックを用意すべきです。想定される異常状態の場合、状況を予測し、ソフトウェアは動作し続けます (ここで動作は、エラーメッセージの出力を意味するかもしれません)。この領域は、ソフトウェアの通常のエラー処理によって対応されます。想定される障害の場合、プログラマーは自信を持って「我々は故障の可能性について認識しており、ソフトウェアは障害が発生した場合でも動作するように設計されています。」とユーザーに伝えるでしょう。
黄色のボックスの外側にある赤色のボックスは、想定外の異常状態と障害を表し、これは未知の領域です。地図上にない領域を航海するようなもので、次に何が起こるのか予想できません。当然、誰もが予測できなかった状況なので、問題の重大さは起こってみなければ分かりません。優れたソフトウェア (または、幸運なソフトウェア) では、リミッターとロジック、そして設計からかけ離れた状態であっても線形に動作する一貫した設計によってそれらが適切に処理されます。”すべてをキャッチする” システムは非常に便利です。ただし、キャッチした後、プログラマーがシステムを安全な状態に移行させる必要があります。しかし、そのようなシステムであっても、これまで長年にわたって例を用いて説明されてきたように、問題が発生する可能性は高いです。
創造性に富んだテスト
テスト環境を考慮して、システムで定義するテストを次のカテゴリーに分類できます。
- 標準動作を確認するためのテスト
- 想定される (システムエンジニアが思いついた) 異常状態と障害のテスト
- 設計者の思いつかない想定外の状況のテスト
想定外のテストというものは存在するのでしょうか? テストが用意されているのではれば、それは想定されていることになります。想定外のテストについては、このシリーズのパート 2 で説明します。
想定される異常状態に戻りましょう。優れたテスターに必要なスキルは、システムに起こりうるものに関して、想像力と創造力が豊かなことです。テストを作成し、実行して、失敗したら (ほとんどの場合は失敗するでしょう)、ソフトウェアを修正します。このプロセスをとおして、ソフトウェアが改善され、システムのロバスト性が向上します。
つまり、優れたテスターは、”想定される異常” と “想定される障害” のセットを拡張して、システムの安定性を改善し、状態と障害のセットを増やして、システムの動作に対する信頼性を高めます。また、次に示すように、想定外の状態のセットを縮小します。
赤色のボックスが排除されるのが理想的です。しかし、実際に稼働しているシステムにおいてそれは可能でしょうか? 実世界では、新しい状況が次々と生み出されます。ソフトウェアが完璧だと思っていても、実際には未知の状況にまだ遭遇していないだけかもしれません。
コンピューティングの歴史から創造力に富んだテストについてお話ししましょう。
ブラックチーム
優れたテスターは、ハッカーのように、システムを壊す方法、壊すのに利用できる脆弱性を見つける方法を考えています。システムの標準動作のテストは、プログラマーでも行うことができるでしょう。実際、開発時には通常の簡単なテストの一部として行われています。前述のとおり、テスターの役割は、明らかなケースだけでなく、プログラマーが思いつかないような状態について考え、それらをテストに組込むことです。
1960 年代 IBM にはブラックチームと呼ばれる有名なテストグループがありました。彼らこそが、想像力豊かなテストを具体化していると思います。当時、IBM は自社ソフトウェアの品質について非常に憂慮しており、有能な人材を集めることで多大な効果が得られるであろうという考えに基づき、社内の選り抜きのテスターでチームを形成しました。その取り組みは、想像以上の成果を上げました。
以下は、http://t3.org/tangledwebs/07/tw0706.html (英語) からの引用の日本語参考訳です。
「… チームメンバーは、自分達に与えられた役割はソフトウェアをテストすることではなく、ソフトウェアを壊すことだと考え始めました。自分達の能力にプライドを持ち、極悪な破壊者として揃って黒いスーツで出社し、自分達を “ブラックチーム” と呼び始めました。」
ブラックチームはコードのテストで素晴らしい成果を上げ、プログラマーから恐れられました。そして、これによりコードの品質が劇的に改善されました。ずさんな仕事をしたら見つかることを知ったプログラマーは、より真剣に注意深くコーディングするようになりました。
このように、ソフトウェアをいじめることこそ、我々がしなければならないことです。特に、我々の生活へのソフトウェアの普及や、セキュリティーの問題、システムへのハッキング、セイフティークリティカルな制御ソフトウェアによる脅威を考慮すると、それは明らかです。
これでパート 1 は終わりです。パート 2 では、テストの実用面と、利用可能なツールとシステムおよびそれらのテストへの影響について述べます。
コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。