シングルトンのテストは難しい、というのはけっこう前から言われているらしく、実際私も嵌りました。
シングルトンだと唯一のインスタンスしかないので、異なるデータでのテストがものすごく書きにくく、複数の小さなテストに分けるのもたいへんです。
私は設定ファイルをシングルトンにすることが多く、インスタンス生成のタイミングで最初に一度だけloadが呼ばれる、というコードを好んで書いていたため、loadが一度しか呼べないので複数のデータを用意できない、という問題が起きました。こんなコードです:
#ifndef HOGEHOGE_CONFIG_INCLUDE #define HOGEHOGE_CONFIG_INCLUDE #include <boost/noncopyable.hpp> class config : boost::noncopyable { public: static config& instance() { static config instance_; instance_.load(); return instance_; } private: void load() { ... } }; #endif // HOGEHOGE_CONFIG_INCLUDE
この問題の解決策として、インクルードガードをundefして、インクルードをnamespaceで囲んじゃえ、という方法をとりました。これで名前空間が異なるconfigクラスが出来上がるので複数のパターンのデータを用意できるというわけです。
#include "config.h" #undef HOGEHOGE_CONFIG_INCLUDE namespace test { #include "config.h" } void config_test() { BOOST_TEST(config::instance()... == ...); } void default_value_config_test() { make_default_value_config(); // テストデータを作成 BOOST_TEST(test::config::instance()... == ...); }
このときはこれで解決しましたが、テストのことを考えるなら、loadはインスタンス生成と分けたほうがいいですね。
それと、この方法はいつでも使えるわけではないので注意。#pragma onceされたらおしまいです。