public static test() メソッドの力
test を書くとき、2つの方法があると思います。
一つは、本番プログラムの外に書く方法。もう一つは本番プログラムの中に書く方法です。
一般的に使われている unittest 系は、前者の外に書く方法です。
んで、ここでは、もう一つの方法、本番プログラムの中にテストを書く方法のメリットとデメリットを書いていきたいと思います。
class MyAdd { private: int Ans; public: //足し算 int Add(int a, int b) { this->Ans = a + b; return this->Ans; } int getAns() const { return this->Ans; } public: //今回説明するメソッド static void test(); } void MyAdd::test() { //テスト1 { MyAdd add; //一度代入するのはVCのウォッチで結果を観察しやすくするため int r ; //1 + 2 = 3 かどうか. ASSERT((r = add.Add(1,2) == 3 )); //前回のテストの結果が保持されているかどうか ASSERT((r = add.getAns() == 3 )); //これが最大のウリ private にも普通にアクセスできます ASSERT((r = add.Ans == 3 )); } //テスト2 { //more... } }
んで、Mainの下にこんな風に書いて呼び出す。
#include "MyAdd.h" void main() { #ifdef DEBUG //テストコードの実行 MyAdd::test(); #endif }
main に 関係ない include が増えまくっていやだという人は、こんな感じで仲介してもいい。
//alltest.cppとかにテストを呼び出す部分をすべて任せる #include "alltest.h" void main() { #ifdef DEBUG alltest(); #endif } //////// //alltest.cpp //////// #include "MyAdd.h" void alltest() { //c++にもリフレクションがほしい... MyAdd::test(); }
こんな感じ。
private にも普通にアクセスできるのが売り。
メリットとデメリットをまとめてみた。
・メリット
- unittest系のライブラリは不要。言語標準の機能だけで簡単に実装可能。
- private メンバにも堂々とアクセスできる
- テストコードでクラスをアクティブかできない問題はあんまりおきない。
- なぜなら、クラス.cpp には、クラスで利用する型はすべて include されているはずだから、利用する型ならどんな型でも呼べる状態になっているから。
- コードとテストが近いので、テストを保守するのが容易
- コードとテストで行ったりきたりがあんまりおきにくい。
- リリースビルドでは、 testコードは呼び出されないので、リンカによって無視されることが期待できる。
- コードを実行するたびにすべてのテストが実行される
- 毎回イヤでもテストを実行させられる。バグの早期発見につながる
・デメリット
- コードとテストが一緒になるので、コードのファイルの行数が増える。
- テスト用のダミークラスを書かなければいけないとき、 test() メソッドの行数が増える。
- インタープリタ言語だと毎回テストコードをパースするコストを払わないといけないかも。。。
- コードを実行するたびにテストが行われるので、遅く時間がかかるテストを入れることはできない。
- 時間がかかるテストコードって言うのがそもそもどうなの。
こんな感じ。
自分はメリットの方がデメリットを上回っていると思うから、結構好きなんだけど、
あんまり使っている人はあんまりいないよね。
これがあるから、unittest の必要性をあんまり感じていないんだ。
コードがドキュメントとか言う人が結構いるぢゃん。コードの中にすべてのドキュメントを埋めていこうって感じ。
コードと仕様書を引き離すのはよくないって考え方。自分はそれに賛同する。
なのに、どうしてコードとテストは引き離される運命なのだろうか。
別に一緒でいいぢゃん。
いろいろ調べてみると、 D言語に unittest っていう構文があってこれと同じようなことをしていた。
他の言語ではどうなのだろうか、また、testunit 信者の意見も聞いてみたい。