CUnitとは
C言語の単体テストのフレームワークです。
プログラム全体を動かしてテストするのではなく、一部分だけ取り出してテストします。
元のプログラムを修正することなく、特定の関数を、引数を変えて繰り返し実行したりすることができます。
仕様通りかの確認というよりは、コーディングミスがないかを確認するためのものです。
そうなるようにコーディングしているんだから動かすまでもない、と思っていても
== が逆(!=)になっている、>= のつもりが > になっているといった誤りは、
実際に動かしてようやく気付くものです。
ダウンロード
CUnitで検索するとSourceForgeの方が出てきますが、このCunity Cunitはその派生プロジェクトのようです。
New Releases of CUnit - 2018-08 Onwards
This is a fork of CUnit from the SourceForge version.
The fork may heal eventually but as of today I have not been able to contact the original maintainers of CUnit.
本家が保守されていない、管理者とも連絡が取れないから立ち上げたようにも読めます。
機能的には大きな違いはないと思いますが、今回はこちらを使います。
インストール
ビルド済みのバイナリは用意されていないので、ソースからビルドします。
CMakeが必要です。
cunit-masterをダウンロードし、C:\cunit-masterに展開したとします。
MinGW(Mingw-w64)でビルドする場合、コマンドプロンプトかPower Shellで
cd C:\cunit-master
mkdir local-build
cd local-build
cmake .. -G "MinGW Makefiles"
cmake --build .
mingw32-make
local-build\CUnit\libcunit.a がCUnitのライブラリです。
実行
Quick Startを見れば基本的な使い方はわかりますが
#include "CUnit/CUnitCI.h"
// テスト対象関数
int func(int arg)
{
return (arg > 0) ? 1 : 0;
}
static void func_test(void)
{
int ret = func(1);
CU_ASSERT(ret == 0);
ret = func(10);
CU_ASSERT(ret == 1);
ret = func(0);
CU_ASSERT(ret == 0);
}
CUNIT_CI_RUN("func"
,CUNIT_CI_TEST(func_test)
);
gcc .\cunit_test.c -lcunit -I C:\cunit-master\CUnit -L C:\cunit-master\local-build\CUnit
実行結果
JUnit XML:
a-Results.xml
Running Suite : func
Running Test : func_test ..PASSED
Run Summary - Run Failed Inactive Skipped
Suites : 1 0 0 0
Asserts : 3 0 n/a n/a
Tests : 1 0 0 0
Elapsed Time: 0.001(s)
ASSERTの内容を変えると、
int ret = func(1);
CU_ASSERT(ret == 0);
FAILEDになります。
Running Suite : func
Running Test : func_test ..FAILED
Suite func, Test func_test had failures:
1. .\cunit_test.c:16 - ret == 0
Run Summary - Run Failed Inactive Skipped
Suites : 1 0 0 0
Asserts : 3 1 n/a n/a
Tests : 1 1 0 0
このように、FAILEDになるのは関数の不具合とは限らず、テストコードの誤りの場合もあります。
いずれにしても、PASSEDになるまで見直しや修正が必要です。
他にどんなASSERTがあるかは、
数値だけでなく、文字列を比較するためのCU_ASSERT_STRING_EQUALもあります。
文字列だけどヌル終端されていない場合の専用ASSERTはないので、以下のようにします。
CU_ASSERT(memcmp(buf, "expected", strlen("expected")) == 0);
面倒だからとテストをさぼると、たいていそこで不具合が出ます。こまめなテストが大事です。