個人的に目から鱗だったのでメモ。
Boost.Testでsetup/teardown的な物を書くにはどうすれば良いのかなーとググって、IT戦記のコメント欄経由でBOOST_FIXTURE_TEST_SUITE()
の存在を知る。
で、ふと該当部分のコードがどうなってるのか気になったので覗いてみた。
以下引用コードは全てBoost 1.45.0のunit_test_suite.hppから。
#define BOOST_FIXTURE_TEST_SUITE( suite_name, F ) \
BOOST_AUTO_TEST_SUITE( suite_name ) \
typedef F BOOST_AUTO_TEST_CASE_FIXTURE; \
/**/
53~56行、BOOST_FIXTURE_TEST_SUITE()
マクロの定義部分。このマクロの第2引数に指定したクラスがfixture実装クラスとなり、コンストラクタがsetup処理、デストラクタがteardown処理になる。利用法は上に挙げたメモの日々(2009-05-26)を参照。
さて、このコードを見ると、fixtureを使わない場合に使用するBOOST_AUTO_TEST_SUITE()
を内部で利用している。BOOST_AUTO_TEST_SUITE()
は44~47行にて定義されており、次のようになっている。
#define BOOST_AUTO_TEST_SUITE( suite_name ) \
namespace suite_name { \
BOOST_AUTO_TU_REGISTRAR( suite_name )( BOOST_STRINGIZE( suite_name ) ); \
/**/
で、実際のテストケースを記述するBOOST_AUTO_TEST_CASE()
マクロは次のように定義されている。114~116行。
#define BOOST_AUTO_TEST_CASE( test_name ) \
BOOST_FIXTURE_TEST_CASE( test_name, BOOST_AUTO_TEST_CASE_FIXTURE )
/**/
BOOST_FIXTURE_TEST_SUITE()
の定義内にてtypedef
されているBOOST_AUTO_TEST_CASE_FIXTURE
が此処で利用されている。
……あれ?でもこれってBOOST_AUTO_TEST_SUITE()
利用時には定義されていない筈だよな?一体どうなってるんだろう?
"BOOST_AUTO_TEST_CASE_FIXTURE
"でコード内を検索すると、以下の記述が見つかる。193~202行。
namespace boost { namespace unit_test { namespace ut_detail {
struct nil_t {};
} // namespace ut_detail
} // unit_test
} // namespace boost
// Intentionally is in global namespace, so that FIXURE_TEST_SUITE can reset it in user code.
typedef ::boost::unit_test::ut_detail::nil_t BOOST_AUTO_TEST_CASE_FIXTURE;
グローバルスコープにて全く同じ名前の型がtypedef
されている。
つまり、BOOST_AUTO_TEST_SUITE()
使用時は、
typedef ::boost::unit_test::ut_detail::nil_t BOOST_AUTO_TEST_CASE_FIXTURE;
namespace test_suite_name {
// 略
BOOST_FIXTURE_TEST_CASE(test_case_name, BOOST_AUTO_TEST_CASE_FIXTURE); // グローバルの物が使われる
// 略
……のように展開され、グローバルスコープに定義されたBOOST_AUTO_TEST_CASE_FIXTURE
が利用される。
が、対してBOOST_FIXTURE_TEST_SUITE()
使用時は、
typedef ::boost::unit_test::ut_detail::nil_t BOOST_AUTO_TEST_CASE_FIXTURE;
namespace test_suite_name {
typedef fixture_class_name BOOST_AUTO_TEST_CASE_FIXTURE;
// 略
BOOST_FIXTURE_TEST_CASE(test_case_name, BOOST_AUTO_TEST_CASE_FIXTURE); // 同じ名前空間内の物が使われる
// 略
……のように展開され、名前空間内のtypedef
に因ってグローバルスコープのBOOST_AUTO_TEST_CASE_FIXTURE
が隠蔽されるようになっているのである。
確かに、このような場合には、より内側の物で外側が隠蔽されると入門書で読んだ記憶があるが、実際に使われているコードを見るのは初めてかも。
目から鱗というか、盲点だったというか。
- setup/teardown
- それぞれ、テスト開始時に必ず行う処理、テスト終了時に必ず行う処理
- Boost 1.45.0
- 2011年5月22日現在、最新のバージョンは1.46.1だが、ものぐさこいてアップデートしてなかった……