意見の相違はあるものの、経験豊富なソフトウェア開発者のほぼ全員が、ソフトウェアテストはいくらあっても足りないということに同意するでしょう。最新のソフトウェアリリースには欠陥がないと思っていたのに、また別の問題に直面するという経験を、私たちは皆したことがあるでしょう。
幸運にも、私は 20 代前半に防衛関連企業で軍事用途のオペレーティングシステム(OS)の開発に携わっていたときに、この貴重な経験を積むことができました。私たちのOSの納品要件には、24 時間のストレステストをエラーなしでクリアすることが含まれていました。
このテストでは、オペレーターがあらゆる方法でOSをロードし、ダウンさせようと試みました。OSをクラッシュさせるという悪評は、すべてのオペレーターにとって大きなモチベーションとなりました。リリース版をストレステストに提出したとき、コードレビューやテストなどにかなりの時間を費やしていたため、問題は発生しないだろうと確信していました。
ところが、最初の 4 時間はすべてが完璧に動作していました。が、その後突然クラッシュしたのです。
私たちは根本的な問題をすぐに修正し、再提出しました。もう問題はないだろうと甘く考えていたのです。しかし、8 時間後に新たな 24 時間テストを開始したところ、別のクラッシュが発生しました。このサイクルが数回繰り返され、ようやく 24 時間ストレステストに合格しました。
このことから私が学んだ教訓は、テストはいくらやっても足りないということです。ソフトウェアには常に欠陥があり、それらはしばしば異なる確率の枠内で顕在化します。
ソフトウェアの欠陥は、ほぼすべてテスト不足に起因します。欠陥を特定するためのテストがないと、欠陥がそのまま本番環境にリリースされてしまいます。そのよくある理由の一つは、テストが後回しにされてしまうことです。
開発者は、期待される出力を達成することだけに集中して、大量のコードを書くことがよくあります。回帰テストスイートはその後になって初めて作成されます。ソフトウェアは一般的な状況では確実に動作するため、誤った安心感を抱く可能性があります。
また、市場に出すためのスケジュールのプレッシャーもあるかもしれません。これらの要因は、完全なテスト環境を作成するための努力に悪影響を及ぼします。
では、テストを改善するにはどうすればよいでしょうか。
テストはソフトウェア開発プロセスにおける後付けの作業から、主要なアクティビティに移行させる必要があります。ここ数年、私はテスト駆動開発 (Test-Driven Development :TDD) のファンになり、すべての開発作業でそれを活用してきました。
この方法論では、テストは実装の前に作成されます。たとえば、PX5 RTOS に POSIX pthread API の pthread_create を実装したとき、この API の簡単なテストから始めました。最初は、pthread_create のコードが書かれていなかったため、テストはコンパイルされませんでした。実装が完成したら、API を徹底的にテストできるようになりました。
実装の完全なコードカバレッジを要求するように TDD を拡張することも、価値のある目標です。たとえば、製品コードベース全体にわたって、ステートメントおよび分岐決定のカバレッジテスト100% の実施を要求するとします。これは標準テストの大幅な拡張です。私が取り組んだ初期のOSでこの方法論を使用していたら、24 時間のストレステストに 1 回目で合格していたかもしれません。
「an ounce of prevention is worth a pound of cure(予防は治療に勝る)」という古い格言は、ソフトウェア開発に間違いなく当てはまります。TDD がアプリケーションにとって最適な選択肢であるかどうかにかかわらず、テストの重要性と徹底性を高めることは、価値のある予防策であることは明らかです。それでも、まだ十分ではありません。