第1回 C++開発者の皆さん。テスト、ちゃんとしていますか?連載 C++開発者のための単体テスト入門(4/4 ページ)

» 2007年07月20日 00時00分 公開
[επιστημη(えぴすてーめー),]
前のページへ 1|2|3|4       

■従来のテスト手法[2]:assertマクロの活用

 ここまでprintf関数を使ったテスト(C++ですからprintf関数ではなく、「<iostream>ライブラリとcoutストリーム」を使うのをお勧めしますが)の手順を説明しましたが、この方法ではテスト対象の増加に伴ってテスト・ケースも次第に増えてきます。

 そうなると、各テスト結果の検証に多くの時間を要することになります。printf関数(あるいはcoutストリーム)で出力しているのは、関数/メソッドが返した値そのものであり、それが正しいか否かを目視でチェックしているのですから、テスト・ケースが数百数千ともなると正直うんざりしますし、チェック・ミスも起こるでしょう。単に値を出力するだけではいずれ限界となるのです。

 そこで、テスト結果をもっと楽に検証するため、標準C++ヘッダ<cassert>に定義されたassertマクロを使ってみます。assertマクロは引数を1つ取り、その値が真(=0以外)であればそのまま次の行へと実行が進みますが、偽(=0)であった場合はそこでプログラムが停止します。

 テスト・コード「abs_math_test.cpp」を以下のコードに差し替えます。

#undef NDEBUG
#include <cassert>
#include "abs_math.h"

using namespace std;

void
abs_compare_test() {

  /* 0 を返すケース*/
  assert(  0 == abs_compare( 2, 2));
  assert(  0 == abs_compare( 2,-2));
  assert(  0 == abs_compare(-2, 2));
  assert(  0 == abs_compare(-2,-2));

  /* 1 を返すケース*/
  assert(  1 == abs_compare( 3, 2));
  assert(  1 == abs_compare( 3,-2));
  assert(  1 == abs_compare(-3, 2));
  assert(  1 == abs_compare(-3,-2));

  /* -1 を返すケース*/
  assert( -1 == abs_compare( 2, 3));
  assert( -1 == abs_compare( 2,-3));
  assert( -1 == abs_compare(-2, 3));
  assert( -1 == abs_compare(-2,-3));
}

int main() {
  abs_compare_test();
  return 0;
}

assertマクロで書き直したabs_compare関数をテストするソース・ファイル(abs_math_test.cpp)

 assertマクロは、シンボル「NDEBUG」が定義されていると、コンパイル時に「assert(……);」という記述そのものがソース・コードに書かれていないのと同じになります。Visual Studioのプロジェクト・プロパティのデフォルト設定では、Releaseモードだと「NDEBUG」が定義されているため、Releaseモードでコンパイルされた際のテスト・コードはまったく機能しなくなってしまいます。そこでReleaseモードでもテストできるよう、テスト・コードの1行目に「#undef NDEBUG」を追加しました。

 「assert」に続く丸カッコの中には「正しい結果が得られたら真となる式」を記述します。

 これをビルドして実行してみましょう。すべてのテストが成功すれば、Releaseモードでは次のような結果となります。

Releaseモードにおけるassertマクロによるテスト「abs_math_test.exe」の実行結果(“期待される振る舞い”)

 何も出力されないことが全テスト成功の証しというわけです。試しに、テスト対象であるabs_compare関数が常に0を返すようなバグをわざと混入させ、Releaseモードで再テストすると、次のような結果になります。

Releaseモードにおけるassertマクロによるテスト「abs_math_test.exe」の実行結果(期待される結果ではない……)
abs_compare関数の実装で、すべて「return 0;」で戻り値を返すようにしたため、期待される結果とはならない。

 このように、assertマクロによるテストに失敗した式とソース名そして行番号が出力されます。ちなみにDebugモード実行では次のようになります。

Debugモードにおけるassertマクロによるテスト「abs_math_test.exe」の実行結果(期待される結果ではない……)
Debugモードでassertマクロによるテストに失敗した場合、デバッグ用の[Microsoft Visual C++ Debug Library]というダイアログが表示される。

 このダイアログの[再試行]ボタンをクリックすると、assertマクロによるテストに失敗した行で、実行にブレイクがかかった状態にすることができます。次の画面は実際にブレイクがかかったIDEの例です。

assertマクロによるテストに失敗した行で実行にブレイクがかかった状態のIDE

 assertマクロを使ったテストだと、「正しく動いていれば真となる式」を並べるだけですし、実行結果の検証作業を一切必要としないので実装(あるいは修正)とテストをリズミカルに反復することができます。

 しかしながらこの手法にも問題がないわけではありません。テストに失敗すると、それ以降のテストを行わずに終了してしまうので、そのテスト・ケースが成功するまで次のテストが行えません。複数のテスト項目を効率よく実行したいならテストの順序を手作業で並べ替えなくてはなりません。

 成功/失敗にかかわらず全テスト・ケースを実行、あるいは全テスト・ケースの中から選択したものだけを実行し、失敗したケースのリストが一度に得られるなら、より効率的な実装/テストが行えることでしょう。次回はこのような要求に応えるべく作られたテスト環境「UnitTest Framework」を紹介します。

「連載 C++開発者のための単体テスト入門」のインデックス

連載 C++開発者のための単体テスト入門

前のページへ 1|2|3|4       

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。