提供されるASSERT群
ヘッダ「WinUnit.h」の中に「WIN_」で始まる一連の検証マクロ群が用意されており、テスト関数内でこれらを使うことでテスト結果の検証を行います。
- WIN_ASSERT_EQUAL(expected, actual, ...)
- WIN_ASSERT_NOT_EQUAL(notExpected, actual, ...)
- WIN_ASSERT_STRING_EQUAL(expected, actual, ...)
- WIN_ASSERT_ZERO(zeroExpression, ...)
- WIN_ASSERT_NOT_ZERO(nonzeroExpression, ...)
- WIN_ASSERT_NULL(nullExpression, ...)
- WIN_ASSERT_NOT_NULL(notNullExpression, ...)
- WIN_ASSERT_FAIL(message, ...)
- WIN_ASSERT_TRUE(trueExpression, ...)
- WIN_ASSERT_FALSE(falseExpression, ...)
- WIN_ASSERT_WINAPI_SUCCESS(trueExpression, ...)
- WIN_ASSERT_THROWS(expression, exceptionType, ...)
expected(期待値)とactual(結果)とが等しい(==)ことを検証します。expected(期待値)とactual(結果)とが等しくない(!=)ことを検証します。expected/actualはchar*もしくはwchar_t*。文字列として等しいことを検証します。zeroExpression==0であることを検証します。nonzeroExpression!=0であることを検証します。nullExpression==NULLであることを検証します。notNullExpression!=NULLであることを検証します。messageを出力します。trueExpressionが真(true,!=0)であることを検証します。falseExpressionが偽(false,==0)であることを検証します。trueExpressionが真であることを検証します。偽のときにはGetLastError()の結果を出力します。expressionを評価中にexceptionType型の例外がthrowされることを検証します。 各WIN_ASSERTの引数に続いてwprintfと同様の書式で失敗時のメッセージを記述できます。例えば、C++標準ライブラリのstd::wstring値を検証するとき、
BEGIN_TEST(string_test1)
{
std::wstring actual = L"間違った答";
WIN_ASSERT_EQUAL(L"正しい答", actual);
}
END_TEST
の結果は
WIN_ASSERT_EQUAL failed. Expected: <0x100187A8> ("L"正しい答"");
Actual: <[OBJECT]> ("actual").
と出力され、actual値をよみとることができません。そこで:
BEGIN_TEST(string_test2)
{
std::wstring actual = L"間違った答";
WIN_ASSERT_EQUAL(L"正しい答", actual, L"actual=[%s]", actual.c_str());
}
END_TEST
としておけばactual値を実行結果から確認できます。
WIN_ASSERT_EQUAL failed. Expected: <0x100187A8> ("L"正しい答"");
Actual: <[OBJECT]> ("actual"). actual=[間違った答]
冒頭で示したCUnitによるユニットテストをWinUnitで書き換えたものを示します:
#include <WinUnit.h> #include "Car.h" namespace { Car c; } // Fixtureの宣言 FIXTURE(car_fixture); // テスト直前に呼ばれる SETUP(car_fixture) { c = car_new(50,2); WIN_ASSERT_NOT_NULL(c); } // テスト直後に呼ばれる TEARDOWN(car_fixture) { car_delete(c); } BEGIN_TESTF(car_init,car_fixture) { WIN_ASSERT_ZERO(car_distance(c)); WIN_ASSERT_ZERO(car_remain(c)); } END_TESTF BEGIN_TESTF(car_refuel,car_fixture) { car_refuel(c, 20); WIN_ASSERT_EQUAL(20,car_remain(c)); car_refuel(c, 20); WIN_ASSERT_EQUAL(40,car_remain(c)); car_refuel(c, 20); WIN_ASSERT_EQUAL(50,car_remain(c)); } END_TESTF
おまけとまとめ
最後にWinUnitのカスタムロガーを紹介しておきましょう。
WinUnitは標準出力だけでなく、ユーザーの好みに合わせたログの出力をサポートしています。#include <WinUnitLogger.h>に続いてあらかじめ宣言された関数を実装し、DLLを作ります。
HTMLを出力する簡単なロガーを書いてみました。
#include <WinUnitLogger.h> #include <fstream> #include <locale> using namespace std ; wofstream* strm; /// 初期化 WINUNIT_LOGGER_FUNCTION(void, Initialize)( const wchar_t* initializationString ///< 初期化文字列 ) { strm = new wofstream(initializationString); strm->imbue(locale("japanese")); *strm << L"<html><body>\n"; } /// テスト前に実行形式名を出力 WINUNIT_LOGGER_FUNCTION(void, OutputTestExecutableNamePreTest)( const wchar_t* fullPath, ///< フルパス const wchar_t* nameOfExecutable ///< 実行形式名 ) { *strm << L"実行形式: " << fullPath << L"(" << nameOfExecutable << L")<br/>\n" << L"<table border='1'><br/>\n"; } /// テスト後に実行形式名を出力 WINUNIT_LOGGER_FUNCTION(void, OutputTestExecutableNamePostTest)( const wchar_t* fullPath, ///< フルパス const wchar_t* nameOfExecutable, ///< 実行形式名 unsigned int succeeded, ///< 成功したテスト数 unsigned int totalRun ///< 実行したテスト数 ) { *strm << L"</table border='1'>\n"; } const wchar_t* widen(const char* str) { static wchar_t buf[512]; wchar_t* dst = buf; while ( *dst++ = (wchar_t)(*str++) ) ; return buf; } /// テスト前にテスト名を出力 WINUNIT_LOGGER_FUNCTION(void, OutputTestNamePreTest)( const char* testName ///< テスト名 ) { *strm << L"<tr><td>" << widen(testName) << L"</td>"; } /// テスト後にテスト名を出力 WINUNIT_LOGGER_FUNCTION(void, OutputTestNamePostTest)( const char* testName, ///< Name of test that was just run. bool passed ///< True if test passed. ) { *strm << L"<td>" << (passed ? L"<font color='green'>成功</font>" : L"<font color='red'>失敗</font>") << L"</td></tr>\n"; } /// トレース出力 /// 今回は省略 /* WINUNIT_LOGGER_FUNCTION(void, OutputTrace)( const wchar_t* message ///< メッセージ ) { } */ /// テスト失敗時のメッセージ出力 WINUNIT_LOGGER_FUNCTION(void, OutputTestError)( const wchar_t* message ///< 詳細な失敗レポート ) { *strm << L"<td><font color='red'>" << message << L"</font></td>"; } /// エラー行出力 WINUNIT_LOGGER_FUNCTION(void, OutputProgramErrorLine)( const wchar_t* message ) { *strm << L"<td><font color='blue'>" << message << L"</font></td>"; } /// 最終結果出力 WINUNIT_LOGGER_FUNCTION(void, OutputFinalResults)( unsigned int succeeded, ///< 成功した数 unsigned int totalRun ///< テスト総数 ) { *strm << L"<font size='+2'>成功したテスト数:" << succeeded << L" テスト総数:" << totalRun << L"</font><br/></body></html>\n"; delete strm; } /// Verboseレベル /// やることないのでコメントアウト /* WINUNIT_LOGGER_FUNCTION(void, SetVerbosity)( unsigned int verbosity ) { } */
WinUnit実行時に「-l」オプションに続いてロガーDLL名を与えて実行すると、テスト結果が「result.html」に出力されます
WinUnit -l WinUnit_Logger.dll:result.html byWinUnit.dll
WinUnitはC/C++をターゲットとした単体テストフレームワークの中ではおそらく最も敷居の低いものの一つでしょう。ビギナーの皆さんにはCUnit/CppUnitのライブラリを構築し英文ドキュメントと格闘するのは相当タフな作業と思われ、それがために単体テストをあきらめるのは残念です。WinUnitで単体テストをエンジョイしてください。

Actual: <[OBJECT]> ("actual").
