先日、C言語用単体テストフレームワークであるCutterの新バージョン1.0.6がリリースされました。(アナウンス)
NEWSにも書いてあるように、今回のリリースでも多くの新機能がありますが、ここではその中でも特におすすめの構造体定義なしで複雑なテストデータを使えるAPIを紹介します。
この新機能によりもっと簡単にデータ駆動テストが書けるようになります。実際、milter managerのテストが簡単に書けるようになりました。
データ駆動テストとは同じテストケースに対して複数のテストパターンを適用するテスト手法です。これにより多くのテストパターンを簡単に書くことができるという利点があります。
例えば、入力された文字列の小文字をすべて大文字に変換するto_upper()関数のテストをするとします。テストデータは以下の3つを考えます*1。
これはこのように書けます。
1 2 3 |
cut_assert_equal_string("HELLO", to_upper("hello")); cut_assert_equal_string("HELLO", to_upper("HelLo")); cut_assert_equal_string("HELLO", to_upper("HELLO")); |
データ駆動テストでは、テストケースはこのようになります。
1 |
cut_assert_equal_string(expected, to_upper(input)); |
このうち、expectedとinputを外部から与えることになります。Cutterではこのように書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
void data_to_upper (void) { #define ADD_DATUM(label, expected, input) \ gcut_add_datum(label, \ "expected", G_TYPE_STRING, expected, \ "input", G_TYPE_STRING, input, \ NULL) ADD_DATUM("all lower", "HELLO", "hello"); ADD_DATUM("mixed", "HELLO", "HelLo"); ADD_DATUM("all upper", "HELLO", "HELLO"); #undef ADD_DATUM } void test_to_upper (gconstpointer data) { const gchar *expected, *input; expected = gcut_data_get_string(data, "expected"); input = gcut_data_get_string(data, "input"); cut_assert_equal_string(expected, to_upper(input)); } |
QtのQtTestLibではこのようになります。 Chapter 2: Data Driven Testingより:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
void TestQString::toUpper_data(QtTestTable &t) { t.defineElement("QString", "string"); t.defineElement("QString", "result"); *t.newData("all lower") << "hello" << "HELLO"; *t.newData("mixed") << "Hello" << "HELLO"; *t.newData("all upper") << "HELLO" << "HELLO"; } void TestQString::toUpper() { FETCH(QString, string); FETCH(QString, result); COMPARE(string.toUpper(), result); } |
ほとんど同じくらいの手間で書けているのではないでしょうか。
テストプログラムは重複があってもいいからわかりやすい方がよい、とよく言われます。しかし、そのために、重複がたくさんある中から、興味がある重複していない部分が見つけづらくなるのは問題かもしれません。データ駆動テストでは、どのようにテストしたいのかがわかりやすいテストケースになる傾向がある気がしています。
多くのテスティングフレームワークはデータ駆動テストをサポートしています。PerlのTest::Base、RubyのRSpec*2、C++のQtのQtTestLibやGoogle Testでもサポートされています。他にもまだまだたくさんあります。
テストデータの入力方法も様々で、テストプログラム中でテストデータを生成するものから、データベースからテストデータを取り出すもの、CSV、Excelなどから取り出すものもあります。
動的に複雑なことができるスクリプト言語、アノテーションなどでメタデータを指定できる最近の言語、トリッキーなC++などでは便利にデータ駆動テストを実行できるテスティングフレームワークは多くあります。しかし、C言語用のフレームワークではそんなになかったのではないかと思います。*3
Cutterに興味がある方は使ってみたり、メーリングリストなどで提案、質問などしてみてください。