Boostテストライブラリ: ユニットテストフレームワーク
受入テストによって、顧客は満足できる。 XPの格言 ホーム テストケース フレームワークの統合 イントロダクションBoostテストライブラリのユニットテストフレームワークは
テストツール を使ったテストケースを作成し、それらを
テストスイート階層内に整理するのを簡便化するツールを提供する。
このフレームワークは、ユーザを面倒なエラー検出・報告作業や変数処理から解放してくれる。
また、フレームワークを初期化したり、コマンドライン引数や環境変数からパラメータを設定したり、
ユーザ提供のinit_unit_test_suite(argc, argv)関数を読んだり、提供されたテストスイートを実行
するmain()関数も提供される。
このフレームワークは、テストツールの表明(assertion)の成功/失敗を
すべて記録し、すべてのテストケース中の実行中のテストケース数というような進捗を表示し、何種類かの
フォーマットの結果レポートを生成することができる。
ユニットテストフレームワークはシンプルなテストから複雑で重要なテストまで使用することができる。
プログラム実行モニターを使用するような、製品コード内ではこの
フレームワークは使用することができない。
このフレームワークはライブラリのオフラインで実装するように設計されている。インライン実装によって、
コンパイルの実行効率が向上する。ユニットテストフレームワークはあたらしいテストプログラムを作成する
間はプログラム実行モニターよりも好きになるべきである。
テスト入門フレームワークコンポーネントユニットテストフレームワークはいくつかの協調して動作するコンポーネントから構成されている。 すべてのコンポーネントはboost::unit_test_framework名前空間に配置されている。 テストケースコンポーネントはシンプルなテストのユニット(単体)という 考えをカプセル化している。 テストスイートコンポーネントは関連するテストユニットをひとまとめにし、 テストのユニットの合成として扱うようにすることができる。 テスト実行中の出力の生成を管理するのには、テストログコンポーネントを使用する ことができる。 テスト結果コンポーネントはテスト結果の表現の責任を持つ。 テストケースユニットテストフレームワークを使用することで、単体の関数やユーザの作成したクラスメソッドなどによる テストケースを作成することができる。以下の4つのテストケースがある:function_test_case, class_test_case, parametrized_function_test_case, parametrized_class_test_case。 これらすべてのテストケースインタフェースの実装は、抽象ベースクラスtest_caseを元に定義されている。 テストケースインタフェース定義unit_test_suite.hpp内で定義されている。 概要class test_case { public: void set_timeout( int timeout ); void set_expected_failures( unit_test_counter exp_fail ); void run(); }; 説明抽象クラスtest_caseはテストケースのインタフェースを定義している。 test_case::set_timeout(...)を使用して、テストケースの タイムアウト時間を設定することができる。 execution_monitor::execute(...)メソッドを見ると、タイムアウト値に関する 詳しい情報がある。test_case::set_expected_failures(...)メソッドを使用すると、 テストケース内での期待するテストツールの失敗数を記述することができる。 ほとんどの場合、このtest_caseをtest_suiteに追加する歳にこれらのパラメータを設定するのが便利であろう。 test_suite::add(...)には詳細情報が書いてある。test_case::run() メソッドを使用すると、テストケースの実行を開始することができる。 構築test_caseクラスのインスタンスを生成する必要はない。
単体の関数ベースのテストケース定義unit_test_suite.hpp内で定義されている。 概要class function_test_case : public test_case { public: function_test_case( void (*function_type)(), char const* name ); ... // 実装 }; 説明もっともシンプルで幅広く使用されるテストケースである。クラスfunction_test_caseのインスタンスは ユーザが指定した、void (*fct)()という型の単独の関数へのポインタを使用して生成される。返り値の型はvoidである。 テスト結果を通知するには、返り値ではなく、テストツールを用いて行う。 構築テスト関数ベースのテストケースを作成するには、以下のマクロを使用する: BOOST_TEST_CASE( &free_function ) BOOST_TEST_CASEはfunction_test_caseクラスの新しいインスタンスを作成し、 基底クラスである、test_caseクラスへのポインタを返す。 このポインタはtest_suite::add(...) メソッドの引数に使用されることが多い。サンプルvoid test_feature1()
{
...
}
...
ts->add( BOOST_TEST_CASE( &test_feature1 ) );
_____________________
#include <boost/test/unit_test.hpp> using boost::unit_test_framework::test_suite; // テストケースを単体の関数として実装する void free_test_function() { BOOST_CHECK( 2 == 1 ); } test_suite* init_unit_test_suite( int argc, char* argv[] ) { test_suite* test= BOOST_TEST_SUITE( "Example" ); test->add( BOOST_TEST_CASE( &free_test_function ) return test; }
クラスメンバー関数ベースのテストケース定義unit_test_suite.hpp内で定義される。 概要template<class UserTestClass> class class_test_case : public test_case { public: class_test_case( void (UserTestCase::*function_type)(), char const* name, boost::shared_ptr<UserTestCase>& user_test_case ); ... // 実装 }; 説明class_test_caseのインスタンスは、メンバー関数と、void (UserTestClass::*fct)()という型を持つ、テストクラスの インスタンスを用いて生成される。同じインスタンスを共有することを許し、一つのテストケースはもう一つの結果を 使用することができるようにするために、class_test_caseはboost::shared_ptrをユーザのテストケースクラスのインスタンス を用いて生成される。同じ効果を以下のような単独の関数を用いても達成することができる: void compount_test() {
UserTestCase instance;
instance.test1();
instance.test2();
...
};
この方式の1つの欠点はテストケースの結果を分離することができないということである。
クラスメンバー関数ベースのテストケースを用いるもう一つの理由は、デフォルトコンストラクタ
を持たないテストケースをテストする場合である。言い換えれば、ユーザテストケースがコマンドライン
引数や、他のパラメータが生成時に必要となる場合である。一般的にはclass_test_caseはテストロジックを
単独の関数に実装することができない場合にのみ使用することを勧める。class_test_caseを実装する例としては、
function_test_caseをより長期間使用するかどうか、ということである。
構築class_test_caseのクラスのインスタンスを生成するには以下のマクロを使用する: BOOST_CLASS_TEST_CASE( function, shared_test_case_instance ). BOOST_CLASS_TEST_CASEは新しい、class_test_caseクラスのインスタンスを作成し、 基底クラスである、test_caseクラスへのポインタを返す。 このポインタはtest_suite::add(...) メソッドの引数に使用されることが多い。サンプルclass my_complex_test { public: void test_feature1() { ... } }; ... ts->add( BOOST_TEST_CASE( &my_complex_test::test_feature1 ) );_______________________________ class class_under_test { public: // iは正でなければならない; それ以外では例外を投げる explicit class_under_test( int i ); ... // アクセスメソッド int get_value() const; }; class compound_test { public: void test_construction() { BOOST_CHECK_THROW( new class_under_test( -1 ) ); v = new class_under_test( 1 ); BOOST_CHECK( v is valid ); ... } void test_access_methods() { BOOST_CHECK_EQUAL( v->get_value(), 1 ); ... } private: class_under_test* v; }; ... boost::shared_ptr<compound_test> instance( new compound_test ); ts->add( BOOST_TEST_CASE( &compound_test::constructor, instance ) ); ts->add( BOOST_TEST_CASE( &compound_test::test_access_methods, instance ) );
パラメータを持つ、独立関数のテストケース定義unit_test_suite.hpp内で定義される。 概要template <typename ParamIterator, typename ParameterType> class parametrized_function_test_case : public test_case { ... // 実装 }; 説明parametrized_function_test_caseクラスのインスタンスはユーザの提供する、 void (*fct)( ParameterType )という型を持つ独立した関数を与えて生成される。 構築parametrized_function_test_caseのインスタンスは以下のマクロで生成する: BOOST_PARAM_TEST_CASE( free_function, first_parameter, last_parameter ). first_parameterとlast_parameterはパラメータのリストの最初のイテレータと最後のイテレータである。 BOOST_PARAM_TEST_CASEはparametrized_function_test_caseクラスの新しいインスタンスを作成し、 基底クラスである、test_caseクラスへのポインタを返す。 このポインタはtest_suite::add(...) メソッドの引数に使用されることが多い。 parametrized_function_test_caseはパラメータのリストを内部に保存することはしない。そのため、テストケースが 実行されるまではパラメータリストは破壊してはならない。そのため、パラメータリストはinit_unit_test_suite のローカル変数に作成しな方が良い。 パラメータリストの寿命を制御するシンプルな方法としては、ユーザ定義のテストスイートクラス内に定義するというのがある。サンプルvoid test_file_reader( std::string const& file_name ) { ... } struct reader_testing : public boost::unit_test_framework::test_suite { void reader_testing() { files_to_test.push_back( "file 1" ); ... files_to_test.push_back( "file N" ); add( BOOST_TEST_CASE( &test_file_reader, files_to_test.begin(), files_to_test.end() ); } std::list<std::string> files_to_test; }; ... ts->add( new reader_testing );
パラメータを持つクラスメンバー関数ベースのテストケース定義unit_test_suite.hppで定義される。 概要template<class UserTestClass, typename ParamIterator, typename ParameterType> class parametrized_class_test_case : public test_case { ... // 実装 }; 説明parametrized_class_test_caseのインスタンスは、void (UserTestClass::*fct)( ParameterType )という型を持つ、 ユーザのテストクラスのメソッドを渡して生成される。parametrized_class_test_caseはユーザのテストクラスの インスタンスの生成と破壊の責任を持つ。 構築parameterized_class_test_caseクラスのインスタンスは以下のマクロで生成する: BOOST_PARAM_TEST_CASE( test_class_method, first_parameter, last_parameter ). first_parameterとlast_parameterはパラメータのリストの最初のイテレータと最後のイテレータである。 BOOST_PARAM_TEST_CASEはparametrized_class_test_caseクラスの新しいインスタンスを作成し、 基底クラスである、test_caseクラスへのポインタを返す。 このポインタはtest_suite::add(...) メソッドの引数に使用されることが多い。 parametrized_class_test_caseはパラメータのリストを内部に保存することはしない。そのため、テストケースが 実行されるまではパラメータリストは破壊してはならない。そのため、パラメータリストはinit_unit_test_suite のローカル変数に作成しな方が良い。 例えば、パラメータリストをファイルスコープ内に置くことができる。サンプルclass my_complex_test { void test_assignment( double tolerance ) { ... } }; ... std::list<double> possible_tolerances; ts->add( BOOST_TEST_CASE( &my_complex_test::test_assignment, possible_tolerances.begin(), possible_tolerances.end() ) );
テストスイート定義defined in unit_test_suite.hpp 概要class test_suite : public test_case { public: void add( test_case* tc, unit_test_counter expected_failures = 0, int timeout = 0 ); ... // Implementation }; 説明
ユニットテストフレームワークでは作成したテストケースをテストスイートでまとめ、任意の深さにテストを階層化することができる。
test_caseをtest_suiteに追加するにはtest_suite::add(...)メソッドを用いる。最初のパラメータは新しいtest_caseのポインタ
であり、ふたつめは期待される失敗の数である。これはテストツールの失敗する表明の数である。
みっつめはテストケースのタイムアウト時間である。期待される失敗の数はテストスイート内で自動的に計算されるため、
アテストスイートを階層に追加する時にいちいち指定する必要はない。
execution_monitor::execute(...)にタイムアウトの詳細な説明がある。
残りのふたつのオプションはオプションであり、値を入れない場合には設定されない。この場合、test_case内で定義された値が使用される。
構築test_suiteクラスのインスタンスを作成するためには以下のマクロを使用する: BOOST_TEST_SUITE( test_suite_name ). BOOST_TEST_SUITEはtest_suiteクラスのインスタンスを作成し、そのポインタを返す。 test_suiteはtest_suiteであり、複数レベルの階層を作成することができる。 テスト結果定義defined in unit_test_result.hpp 概要class unit_test_result { static unit_test_result& instance(); void confirmation_report( std::ostream& where_to ); void short_report( std::ostream& where_to ); void detailed_report( std::ostream& where_to ); int result_code(); }; 説明ユニットテストフレームワークはテスト結果をunit_test_resultクラスのインスタンスとして保持する。 unit_test_resultクラスは3つのメソッドを結果報告のために持っている。 unit_test_result::confirmation_report(...)は成功/失敗のメッセージのみを報告する。 unit_test_result::short_report(...)は現在のテストケースの結果を報告する。 このレポートには成功や失敗したテストの数、失敗したテストツール表明などが含まれる。 unit_test_result::detailed_report(...)メソッドはこれらが含まれる、すべてのテストの結果を返す。 ほとんどの場合ではこれらのインタフェースを直接利用することはないだろう。 テスト結果の報告はフレームワークによって自動的に行われる。 構築
unit_test_resultクラスのインスタンスにアクセスするには、
静的なunit_test_result::instance()メソッドを使用する。
テストログ定義unit_test_log.hpp内で定義される。 概要class unit_test_log { static unit_test_log& instance(); void set_log_stream( std::ostream& str ); void set_log_threshold_level_by_name( char const* lev ); }; 説明テスト出力ストリームを管理するために、ユニットテストフレームワークではunit_test_logというシングルトンクラスを使用している。 テスト出力ストリームを変更するためにはunit_test_log::set_log_stream(...)メソッドを使用する。 デフォルトのストリームはstd::coutである。 ログレベルを変更するにはunit_test_log::set_log_level_by_name(...)メソッドを使用する。 ほとんどの場合はこのインタフェースを直接利用することはない。 ログレベルの変更はテストプログラムの外部から簡単に行えるようになっている。 このパラメータと設定可能な値はフレームワークのパラメータを参照。 構築
unit_test_logクラスのインスタンスにアクセスするには、
静的なunit_test_log::instance()メソッドを使用する。
テストモニターテストケースの実行を監視するために、ユニットテストフレームワークはunit_test_monitorクラスを使用する。 unit_test_monitorはtest_caseのメソッドを、実行モニター下で実行させる。 この環境では、execution_monitor例外を指定されたエラーコードに変換する。 unit_test_monitorクラスの詳細はBoostテストライブラリ設計に書いてある。 ほとんどの場合ではテストケースが実行される場合にはすでに監視が行われるため、unit_test_monitorを使用するコードを書く必要はない。 フレームワークの統合説明ユニットテストフレームワークはテスト環境を整備し、結果の報告まで行うmain関数が用意されているという説明を行った。 ユーザが提供する関数へのフックもこのmain関数には含まれている。 以下の形式を持つ関数を定義することでユーザ提供の関数とフレームワークは統合される: boost::unit_test_framework::test_suite* init_unit_test_suite ( int argc, char* argv[] ) この関数はtest_suiteクラスのルートのインスタンスを初期化するのに使用するべきである。 NULLポインタをこの関数で返すと、初期化されていないtest_suiteとして扱われる。 この場合はフレームワークは提供されているtest_suiteクラスのインスタンスで実行を行い、 プログラムの最後で破壊される。そのため、そのインスタンスは動的に割り当てられていなければならない。 コマンドライン引数はフレームワークで使用されるオプションというように保障されるわけではない。 テストケースが実行されると、フレームワークは結果を報告し、リターンコードを返す。 テストプログラムから返された返り値のリストはユニットテストフレームワークで統合される:
サンプルtest_suite* init_unit_test_suite( int argc, char* argv[] ) { test_suite* test= BOOST_TEST_SUITE( "Master test suite" ); test->add( BOOST_TEST_CASE( &my_test_function ) ); return test; }
フレームワークのパラメータユニットテストフレームワークは外部からテストプログラムを設定する方法を二つ用意している。 コマンドライン引数と、環境変数である。以下のテーブルはフレームワークのパラメータを列挙したものである。 環境変数、コマンドライン引数のどちらも設定しなかった時のデフォルト値は、太字であらわしてある。
フレームワークのコンパイルユニットテストフレームワークはオフラインのライブラリ、あるいはテストプログラムに対してリンクするという、ふたつの方法がサポートされている。 Boostテストライブラリのソースディレクトリにある、以下のファイルがフレームワークに含まれる: execution_monitor.cpp また、フレームワークを構成するすべてのファイルをテストモジュールに直接インクルードする方法もある。 <boost/test/included/unit_test_framework.hpp>のファイルを、この目的で使用することができる。 サンプルとテストプログラム
|