Unity覚書(unit test harness)


Unity覚書(Unit Test Harness)

組み込みでテスト駆動開発がしたくなったので勉強を始めました。
参考書
覚書を作成しています。

Unity

UnityはC専用のテストハーネスです。
ゲーム開発エンジンを期待された方は申し訳ありませんが、
本稿では取り扱いませんのでよろしくお願いします。

環境

私の作業場所で扱う計算機が下記の様に異なりますが、
特に区別せずに作業しています、ご了承ください。

  • Debian8 bash gcc-4.9.2
  • macOS-X bash Apple LLVM version 8.1.0 (clang-802.0.42)

利用するUnityはテキストで扱われている
James Grenning氏によって機能追加がされている物を使います。
C開発環境はテキストでいうところの"gcc users"です。

準備

上記参考書のWEBサイトから手に入るソース内にある、
README.txtに書かれていた手順で準備を行いました。
README.txtに書かれていなかった事や備考を列挙します。

  • cpputestのバージョンは3.8をDLしました。
  • configure.shが見当たらなかったので代わりにconfigureを直接実行しました。
  • テストの結果として幾つかfailuresが出ましたがテキスト内で修正する項が出るのを期待し無視しました。※1
  • CppUTestを試した際にCppUTest内(メモリリーク検出マクロ(?))でlonglong型に対するエラー(C90ではサポートされていない)が出たためCppUTestのMakefileWorker内でCCに-std=c99を追加しました。

※1 試しにt0のテストで出たfailuresはtests/HomeAutomation/RandomMinuteTest.cppの
CHECK(hit[i] > 0) failedの条件を=>にしたところfailuresがなくなったので
このまま様子を見ることにします。

Unityの概要

実行

Unityの実体はunity.frameworkに入っており、
提供されるmakefileを自分のmakefile(必要な変数を定義)にincludeすることで
コンパイル、必要なオブジェクトとのリンク、実行を行ってくれます。

記述

テストは下記の構造で記述します。

  • Test Case:事前条件の用意→対象コードの実行→事後条件の確認を行う
  • Test Fixture:Test Case用の共通部分や環境
  • Test Runner:Test Caseの呼び出し

マクロ

代表的なマクロは以下の通りです。

Test Case

macro memo
TEST(TestGroupName, TestName) TestRunnerが呼び出すテストの内容を記入
TEST_ASSERT_TRUE(condition) ブール条件が真か確認する
TEST_ASSERT_FALSE(condition) ブール条件が偽か確認する
TEST_ASSERT_EQUAL(num1, num2) 数値を比較して同じか確認する
TEST_ASSERT_EQUAL_INT(num1, num2) 整数を比較して同じか確認する
TEST_ASSERT_EQUAL_STRING(str1, str2) 文字列を比較して同じか確認する
TEST_ASSERT_BYTES_EQUAL(b1, b2) 1byte分比較してが同じか確認する
TEST_ASSERT_POINTES_EQUAL(p1, p2) ポインタを比較してが同じか確認する
TEST_ASSERT_FLOAT_WITHIN(f1, f2, tolerance) floatを指定した許容範囲内で同じか確認する
TEST_ASSERT_MESSAGE(text) テストを失敗させた後、メッセージ出力する
TEST_ASSERT_EQUAL_HEX16(b1, b2) 16bit分比較してが同じか確認する

Test Fixture

macro memo
TEST_GROUP(TestGroupName) TestGroupを用意
TEST_SETUP(TestGroupName) TestGroupに対するテスト開始時の処理
TEST_TEAR_DOWN(TestGroupName) TestGroupに対するテスト終了時の処理

Test Runner

macro memo
TEST_GROUP_RUNNER(TestGroupName) TestRunnerを用意(TestCaseを登録してTEST_SETUP(TestGroupName)とTEST_TEAR_DOWN(TestGroupName)が呼び出されるようにする)
RUN_TEST_CASE(TestGroupName, TestName) TestCaseを呼び出す
RUN_TEST_GROUP(TestGroupName) 指定したTestGROUPを実行する

※RUN_TEST_GROUPを実行する関数をUnityMainの第3引数に渡して実行します。

#include "unity_fixture.h"

static void
RunAllTests(void)
{
    RUN_TEST_GROUP(sprintf);
}

int
main(int argc, char * argv[])
{
    return UnityMain(argc, argv, RunAllTests);
}

出力

テストに失敗するとFailuresに計上されます。
すべてのテストが成功するとOKと出力されます。

Running BookCode_Unity_tests
Unity test run 1 of 1
..
-----------------------
2 Tests 0 Failures 0 Ignored
OK