2. テスト駆動開発 (TDD)¶
2.2. テスティングフレームワーク¶
[Gre00] ではテスティングフレームワーク [1] に Unity および CppUTest が紹介されているが、特に実機でユニットテストを 実行したいという要求がない限り、本ドキュメントは GoogleTest [2] の使用を推奨する。以下、GoogleTest の使用を推奨する理由を述べる。
- アサーション (Assertion)
GoogleTest では、 JUnit 由来の、アサーション ASSERT_THAT() を使用することができる。 ASSERT_THAT() は、以下に示す通り比較的自然言語に近い形で表記することができる。 ここに示す以外にも、豊富なマッチャーが用意されているので、 適宜 本家の情報 を参照のこと。
#include "gtest/gtest.h" #include "gmock/gmock.h" ... using ::testing::Eq; using ::testing::Gt; TEST(ClassA, Func_returns_0) { ClassA classA; ASSERT_THAT(classA.Func(), Eq(0)); // classA.Func() == 0 } TEST(ClassB, Func_returns_greater_than_5) { ClassB classB; ASSERT_THAT(classB.Func(), Gt(5)); // classB.Func() > 5 }
- 値をパラメータ化したテスト (Value Parameterized Tests)
境界値テストを実施する場合、以下のアプローチを取ることが一般的である。
- パラメータのみ変えたテスト関数を複数用意する
- ひとつのテスト関数に複数のテストをまとめる
しかしながら、これらのようなアプローチをとった場合、1点目はテストコードの冗長化を招き、 2点目はテスト関数の意図が不明確になるデメリットがある。 これに対し、GoogleTest には「値をパラメータ化したテスト」と呼ばれる機能があり、ひとつの テスト関数で複数のテストを実行することができる。 まず、 [Gre00] で紹介されている LedDriver クラスのテストコード (CppUTest版) を示す。
TEST(LedDriver, OutOfBoundsTurnOffDoesNoHarm) { LedDriver_TurnAllOn(); LedDriver_TurnOff(-1); LedDriver_TurnOff(0); LedDriver_TurnOff(17); LedDriver_TurnOff(3141); LONGS_EQUAL(0xffff, virtualLeds); }
上記のテスト関数は、範囲 (1~16) 外のIDを与えた場合はLEDの状態が変更されないことを テストするものであるが、4回の LedDriver_TurnOff() の呼び出し中に、LEDが意図しない 状態となっていないことを保証することができない。 次に、上記関数を GoogleTest に移植したテストコードを示す。
#include "gtest/gtest.h" #include "gmock/gmock.h" ... using ::testing::Eq; class LedDriverTest : public ::testing::Test { protected: ... }; class all_leds_turn_off : public LedDriverTest {}; class arg_pattern_test_when_all_leds_turn_off : public all_leds_turn_off, public ::testing::WithParamInterface<int> {}; TEST_P(arg_pattern_test_when_all_leds_turn_off, TurnOn_does_no_harm) { LedDriver_TurnAllOn(); const int n = GetParam(); // RuntimeErrorモックに対し、期待する振る舞いを指定 // 本説明では不要であるため省略 LedDriver_TurnOff(n); ASSERT_THAT(virtualLeds_, Eq(0xffffu)); } INSTANTIATE_TEST_CASE_P( aPatternInstance, arg_pattern_test_when_all_leds_turn_off, ::testing::Values(-1, 0u, 17u, 3141u));
記述の詳細は本家ドキュメントに譲るが、GoogleTest 版では、上記のようにテスト関数を 実装することで、1パラメータごとにテストを実行することができ、LEDが意図しない状態に なっていないことを確実に保証することができる。 その他、組み合わせテストのパラメータ生成に非常に有効な Combine() というパラメータ 生成関数が用意されている。
- GoogleMock
- [Gre00] ではテストダブルを実装するための手法が複数紹介されているが、GoogleTest の拡張 フレームワーク GoogleMock を使用すれば同等以上のテストが実施できる。
ここまでに紹介した GoogleTest の利点をより読者に感じていただくため、 [Gre00] の サイト で配布されているコードを GoogleTest に 移植した。 GitHub で公開している ので、ぜひ一読いただきたい。
2.3. ユニットテストコード¶
以下を参考に、プロジェクトごとにルールを定めることを推奨する。
2.3.1. コーディングルール¶
原則 Google C++ Style Guide を基本とする。 ただし、C++11/14で追加された機能に対する制限はしないものとする。
また、命名規則は一部変更する。
- メソッド (メンバ関数)
- public、protectedパスカルケース
- privateキャメルケース
- フィールド (メンバ変数)
- publicプレフィックス「k」でパスカルケース、最後にアンダーバー※定数(const、constexpr)以外の宣言は禁止する。
- protectedパスカルケースで最後にアンダーバー
- privateキャメルケースで最後にアンダーバー