CUnit を使う

2018年10月5日

はじめに

C 言語用のユニットテストフレームワークである CUnit の使い方について。

環境

Ubuntu 16.04 LTS

インストール

$ sudo apt-get install libcunit1-dev

使用例

関数を 1 つ持つモジュールを考える。

module.c

#include "module.h"

int func(void)
{
    return 1;
}

#include "module-test.h"

関数 func() は 1 を返す。最後でテストコードを取り込んでいる。テストコードは次のように書く。

module-test.h

#include <CUnit/CUnit.h>

static int Test_init(void)
{
    return 0;
}

static int Test_term(void)
{
    return 0;
}

static void Module_func(void)
{
    CU_ASSERT_EQUAL(func(), 1);
}

void Module_test_register(void)
{
    CU_pSuite suite;
    suite = CU_add_suite("Module", Test_init, Test_term);
    CU_add_test(suite, "func", Module_func);
}

テストの本体は Module_func() で、func() が 1 を返すことを確認している。Module_test_register() でテストを登録している。ヘッダーファイルは次のとおりである。

module.h

#ifndef MODULE_H
#define MODULE_H

int func(void);

void Module_test_register(void);

#endif /* MODULE_H */

テストの main() 関数は次のようにする。

unit_test.c

#include <CUnit/Basic.h>
#include "module.h"

int main(void)
{
    CU_initialize_registry();

    Module_test_register();

    CU_basic_run_tests();
    CU_cleanup_registry();

    return 0;
}

Module_test_regsiter() を呼び出して module のテストを登録している。CU_basic_run_tests() でテストが実行される。Makefile は次のようになる。

Makefile

all:
    gcc -o unit_test unit_test.c module.c -lcunit

コンパイル、実行。

$ make
$ ./unit_test


     CUnit - A unit testing framework for C - Version 2.1-3
     http://cunit.sourceforge.net/



Run Summary:    Type  Total    Ran Passed Failed Inactive
              suites      1      1    n/a      0        0
               tests      1      1      1      0        0
             asserts      1      1      1      0      n/a

Elapsed time =    0.000 seconds

テストが 1 つ実行され、パスしている。

試しに func() の返り値を 0 にしてみよう。

module.c

int func(void)
{
    return 0;
}

コンパイル、実行。

$ make
$ ./unit_test


     CUnit - A unit testing framework for C - Version 2.1-3
     http://cunit.sourceforge.net/


Suite Module, Test func had failures:
    1. module-test.h:15  - CU_ASSERT_EQUAL(func(),1)

Run Summary:    Type  Total    Ran Passed Failed Inactive
              suites      1      1    n/a      0        0
               tests      1      1      0      1        0
             asserts      1      1      0      1      n/a

Elapsed time =    0.000 seconds

テストが失敗したことがわかる。

実用的には、プログラムのコンパイル時に自動的にテストを実行するのがよいのだろう。たとえば、Makefile を次のようにすればよいかもしれない。

Makefile

LIBS = -lcunit
OBJS = module.o

all: prog unit_test

prog: prog.o $(OBJS)
    gcc -o $@ $^ $(LIBS)

unit_test: unit_test.o $(OBJS)
    gcc -o $@ $^ $(LIBS)
    ./unit_test

.c.o:
    gcc -c $<

コンパイル。

$ make
gcc -c prog.c
gcc -c module.c
gcc -o prog prog.o module.o -lcunit
gcc -c unit_test.c
gcc -o unit_test unit_test.o module.o -lcunit
./unit_test


     CUnit - A unit testing framework for C - Version 2.1-3
     http://cunit.sourceforge.net/


Suite Module, Test func had failures:
    1. module-test.h:15  - CU_ASSERT_EQUAL(func(),1)

Run Summary:    Type  Total    Ran Passed Failed Inactive
              suites      1      1    n/a      0        0
               tests      1      1      0      1        0
             asserts      1      1      0      1      n/a

Elapsed time =    0.000 seconds

自動的にテストが実行され、コンパイルは成功したがテストには失敗したことがわかる。