第1回 C++開発者の皆さん。テスト、ちゃんとしていますか?:連載 C++開発者のための単体テスト入門(1/4 ページ)
人海戦術による膨大な手動テスト、やっていませんか? 一般的なテスト方法を振り返り、より効率的な手法を考える新連載。
「ビッグバン・テスト」をご存じですか? アプリケーション全体を構築する数千行、数万行に及ぶコードをコンパイルし、いきなり全体を走らせてその動作を確認するテスト手法です。われわれプログラマーが絶対に過ちを犯さないならともかくも、そうではない現実を考えると、このようなビッグバン・テストは極めてつたないテスト法です(そもそも過ちを犯さないなら、テストの必要はないのですけど)。
テストとは、ひと言でいってしまえば「思ったとおりに動くかを検証すること」でしょうね。プログラムは思ったとおりには動きません。作ったとおりに動きます。従って、「思ったとおりに動くか」の検証とは「思ったとおりに作られているか」の検証にほかなりません。
ビッグバン・テストでも「思ったとおりに動くか」を、仕様書に記された膨大な量の“期待される振る舞い”を基に1つ1つ検証していきます。これによって得られるのは特定の入力を与えたときの“実際の振る舞い”です。“実際の振る舞い”が仕様書に記された“期待される振る舞い”と一致するなら「思ったとおりに動く」ことが確認されたことになります。確かにテスト項目すなわち仕様書に記された膨大な量の“期待される振る舞い”を「単に確認するだけ」なら、人海戦術なり三日三晩ぶっ続けで検証することで、テストを完了できるかもしれません。しかしソフトウェア開発におけるテストは、「単に確認するだけ」では済まされず、「期待に反する振る舞い(すなわち不具合)を見つけたら、その理由/原因を突き止め、その不具合を解消」しなければなりません。
コードがそんなに大量でなければ、不具合の個所を突き止めるのはそう難しくはないでしょう。しかし数千、数万行となると、原因究明は困難を極めます。テストで知ることができるのは“現象”にすぎません。“現象”から“原因”を突き止めなければなりませんが、その“現象”を引き起こす“原因”は1つとは限りません。さまざまな原因が絡み合ってその“現象”を引き起こしているのかもしれません。
テスト対象が広範になればなるほど、“原因”の究明とその修正が困難になります。コードの量が少ない時点でテストしていれば、短時間に見つかったであろう不具合も、大量のコードをテスト対象にすると、原因の特定に手間暇を要します。さらにその原因を取り除こうにも、修正によってはほかの部分に影響が生じて、また新たな不具合を生むことも少なくありません。“あちらを立てればこちらが立たず”で、まるでモグラたたきの様相を呈することもまれではないのです。
ビッグバン・テストにならざるを得ない要因はいくつかあるでしょう。典型的な要因は“時間不足”でしょうか。スケジュールが遅れに遅れ、後工程にそのしわ寄せが集中してしまうのですね。そうなってくると、たとえテストで不具合が見つかっても正しい修正すらできなくなってしまいます。“原因”の究明にかける時間すら惜しくなりますから。
その結果、不具合の修正が“対症療法”となりがちです。頭痛の原因が脳腫瘍(しゅよう)かもしれないのに、“頭痛薬”を飲ませて済ませたり、骨折しているのにばんそうこうを貼って見た目の傷をふさいでしまったりするように。テストには修正(つまりデバッグ)が付きものなのに、それに要する人と時を予定の外に追い出してテストを無理やり通しても(見た目は立派な)粗悪品を世に出すことになってしまいます。発見が遅れるほど治療が難しくなるのですよ。
裏返せば、早期のうちにテストした方が効率もいいし、修正も楽です。「早期のうち」であればテストの対象が小さいのですから、“原因”の究明と修正が楽なのは当然です。対象が小さいので、複数の原因が絡み合うことも少なくなります。これを突き詰めれば、「関数を1つ書いたらすぐテスト」するのが最も早く、楽で、安全ということになります。
そうやって逐一テストされた“信頼できる関数”のみを呼び出すことで、振る舞いを実現する関数のテストもまた楽になります。新たに書かれた部分以外はすべてテスト済みの“信頼できる関数”なのですから、バグがあるとすれば新たに書かれた部分以外にはあり得ません。そうやって“信頼できる関数”だけを積み上げ、“常に信頼できる状態”を維持しながら実装を進めていくのが望ましい開発形態ということになります。
“常に信頼できる状態”を維持する最善の方法は“頻繁にテストする”ことです。ほんの少しでもコードに変更を加えたらすぐさまテストし、必要に応じてテスト自体にも追加/変更を加えることで、“常に信頼できる状態”を維持します。
ここで1つ注意。テスト=デバッグではありません。テストとは“期待される振る舞い”と“実際の振る舞い”との相違、すなわち不具合を検出することであり、片やデバッグとは検出された不具合の情報を基にその原因を見つけて修正することです。ですからテストの不備や抜けをデバッグで穴埋めできるわけではありません。体の異常を訴えない限り、お医者さんは診察/治療できません。「年に一度は健康診断を受けましょう」とは「頻繁にテストしましょう」と同義なのですね。早期発見/早期治療が健康維持の秘訣(ひけつ)というわけです。
そこで本連載ではC++開発のテスト手法について解説します。まずはC++における基本的なテスト手法について振り返ってみましょう。
Copyright© Digital Advantage Corp. All Rights Reserved.