C言語によるアジャイル開発とテスト駆動開発(CI入門) ~ 2.CUnit導入 ~

# 概要
アジャイル開発とテスト駆動開発の関係について理解できたので、ここからは実践です。
今回は、CUnitを導入し実行していくところまで行こうと思います。

## 記事の全体像
- [C言語によるアジャイル開発とテスト駆動開発(CI入門) ~ 1.概念 ~](https://qiita.com/denden14/items/a1435a225e386c32dab5)
- [C言語によるアジャイル開発とテスト駆動開発(CI入門) ~ 2.CUnit導入 ~](https://qiita.com/denden14/items/27d29735caef9b5639e0)
- [C言語によるアジャイル開発とテスト駆動開発(CI入門) ~ 3.CMake導入 ~](https://qiita.com/denden14/items/7b1729c7ff273c4165bd)
- [C言語によるアジャイル開発とテスト駆動開発(CI入門) ~ 4.Jenkins導入 ~](https://qiita.com/denden14/items/30cbe6d327a404aaa2a7)

## 環境
OS : Linux ubuntu 18.04.5 LTS
テストツール : CUnit 2.1-3

コンパイラ : gcc 7.5.0



# xUnitとは
[xUnit](https://ja.wikipedia.org/wiki/XUnit) とは、ソフトウェアの単体テスト(Unit Test)を行うためのフレームワークの総称です。
これらを使うことで、ソフトウェアの様々な要素を簡単にテストすることが可能になります。
本記事で扱うCUnit(C)以外にも、JUnit(Java), PyUnit(Python), PHPUnit(PHP)等様々なフレームワークが存在します。

## xUnitを導入するメリット
- テストが自動化できる
- 同じテストを何度も書かなくて良い
- ここのテスト結果がどうあるべきかを覚えなくて良い

# CUnit導入
では早速CUnitを導入して行きましょう。

[CUnitのURL](https://sourceforge.net/projects/cunit/)

最新版が2.1-3ですので、2.1-3を下記コマンドでインストールします。
環境が異なる方は適宜インストールして展開してください。

```bash:Bash
wget http://jaist.dl.sourceforge.net/project/cunit/CUnit/2.1-3/CUnit-2.1-3.tar.bz2
```

フォルダを解凍します。

```bash:Bash
tar xvf ./CUnit-2.1-3.tar.bz2
cd CUnit-2.1-3/
```

解凍したフォルダの中の`README`を参考にしながら進めます。

```text:README
Linux:

  In addition to jam, the standard GNU build system is still supported.
  The usual sequence of steps should succeed in building and installing CUnit:
    1. aclocal  (if necessary)
    2. autoconf (if necessary)
    3. automake (if necessary)
    4. chmod u+x configure (if necessary)
    5. ./configure --prefix <Your choice of directory for installation>
    6. make
    7. make install

  What's installed:
    1. libcunit.a (Library file)
    2. CUnit Header files
    3. DTD and XSL files supporting xml output files in share directory
    4. Man Pages in relevant man directories under the installation path.
    5. HTML users guide in the doc subdirectory of the installation path.
    6. Example & test programs in the share subdirectory of the install path.
```

分かりづらかったため、エラー発生時のみ実行結果も載せています。

フォルダ内に `aclocal.m4`があるので、 aclocalコマンドは不要かもしれないです。
ワーニングなので、とりあえず進めます。

```bash:Bash
$ aclocal
aclocal: warning: autoconf input should be named 'configure.ac', not 'configure.in'
```

autoconfでエラーが出ました。
エラー内容ぐぐると、libtoolをインストールしろとのこと。

```bash:Bash
$ autoconf
configure.in:161: error: possibly undefined macro: AC_PROG_LIBTOOL
      If this token and others are legitimate, please use m4_pattern_allow.
      See the Autoconf documentation.

$ sudo apt install libtool -y
```

autoconfでエラー出た場合は、`autoreconf`が必要らしい。。。

```bash:Bash
$ autoreconf -i
```

もう一度autoconfから

```bash:Bash
$ autoconf
$ automake
$ ./configure
$ make
$ sudo install
```

環境変数LD_LIBRARY_PATHを設定する。
永続化させる場合は、同様の記述を`.bashrc`に記述してください。

```bash:(Bash)or(.bashrc)
export LD_LIBRARY_PATH=/usr/local/lib
```

`.bashrc`の場合は反映を忘れずに

```bash:Bash
source ~/.bashrc
```

# テストの記述
いよいよテスト駆動開発を始めます。
[CUnit User Guide](http://cunit.sourceforge.net/doc/index.html)を適宜確認しながら記述していきます。

CUnitの一般的な流れは下記の様な流れになります。

1. テスト関数の記述(suite, init/cleanup が必要な場合も記述)
1. テスト構造を初期化 (CU_initialize_registry())
1. テストスイートの追加(CU_add_suite())
1. テスト関数の追加 (CU_add_test())
1. 適切なインターフェースを使用してテストを実行。(例）CU_console_run_tests)
1. テスト構造体のクリーン (CU_cleanup_registry())

テスト関数を下記のように記述しました。

```c:unitTest.c

#include <CUnit/CUnit.h>
#include <CUnit/Console.h>

// バグのあるadd関数(テスト対象)
int add(int x, int y) {
	return 0;
}

/**
 * addテストスイート
 **/
// テスト関数001
void test_add_001(void) {
	CU_ASSERT_EQUAL(add(1, 2), 3);
}

// テスト関数002
void test_add_002(void) {
	CU_ASSERT_EQUAL(add(-1, -2), -3);
}

// main関数
int main() {
CU_pSuite add_suite;

    CU_initialize_registry(); // 2.テスト構造の初期化
    add_suite = CU_add_suite("add", NULL, NULL); // 3.テストスイートの追加
    CU_add_test(add_suite, "test_001", test_add_001); // 4.テスト関数の追加
    CU_add_test(add_suite, "test_002", test_add_002); // 4.テスト関数の追加

    CU_console_run_tests(); // 5.適切なインターフェースを使用してテストを実行
    CU_cleanup_registry(); // 6.テスト構造のクリーン
}
```

# ビルドと実行
さあ、ビルドしましょう

```bash:Bash
$ gcc unitTest.c -Wall -L/usr/local/lib -lcunit -o unitTest
$ ./unitTest

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


***************** CUNIT CONSOLE - MAIN MENU ******************************
(R)un  (S)elect  (L)ist  (A)ctivate  (F)ailures  (O)ptions  (H)elp  (Q)uit
Enter command: r

Running Suite : add
     Running Test : test_001
     Running Test : test_002

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

Elapsed time =    0.000 seconds


***************** CUNIT CONSOLE - MAIN MENU ******************************
(R)un  (S)elect  (L)ist  (A)ctivate  (F)ailures  (O)ptions  (H)elp  (Q)uit
Enter command: 
```

上手く行った。やったぜ〜。

# おまけ
## テスト対象を別ファイルに分割する
上手くCUnitを導入できました。
でも、現状はテストコードとテスト対象コードが同じファイルに存在しています。
これでは実用的ではないですね。
なので、分割します。

`unitTest.c`内で定義していた`add()`を`add.c`に抽出し、
`add()`の定義を`add.h`に持ってきました。

```c:add.c
#include "add.h"

// バグのあるadd関数(テスト対象)
int add(int x, int y) {
		return 0;
}
```

```c:add.h
// #ifndef ADD_H_
// #define ADD_H_

int add(int x, int y);

//  #endif /* ADD_ */
```

```unitTest.c
#include <CUnit/CUnit.h>
#include <CUnit/Console.h>

#include "add.h"

/**
 * addテストスイート
 **/
// テスト関数001
void test_add_001(void) {
	CU_ASSERT_EQUAL(add(1, 2), 3);
}

// テスト関数002
void test_add_002(void) {
	CU_ASSERT_EQUAL(add(-1, -2), -3);
}

// main関数
int main() {
CU_pSuite add_suite;

    CU_initialize_registry(); // 2.テスト構造の初期化
    add_suite = CU_add_suite("add", NULL, NULL); // 3.テストスイートの追加
    CU_add_test(add_suite, "test_001", test_add_001); // 4.テスト関数の追加
    CU_add_test(add_suite, "test_002", test_add_002); // 4.テスト関数の追加

    CU_console_run_tests(); // 5.適切なインターフェースを使用してテストを実行
    CU_cleanup_registry(); // 6.テスト構造のクリーン
}
```

もう一度コンパイルします。

```bash:Bash
gcc add.c unitTest.c -Wall -L/usr/local/lib -lcunit -o unitTest 
```

実行

```bash:Bash
$ ./unitTest
     CUnit - A Unit testing framework for C - Version 2.1-3
             http://cunit.sourceforge.net/


***************** CUNIT CONSOLE - MAIN MENU ******************************
(R)un  (S)elect  (L)ist  (A)ctivate  (F)ailures  (O)ptions  (H)elp  (Q)uit
Enter command: r

Running Suite : add
     Running Test : test_001
     Running Test : test_002

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

Elapsed time =    0.000 seconds
```


## テストを自動実行にする
いい感じになってきました。
あとは、テストを対話型ではなく、自動実行にしたいです。
そのためには、unitTest.cの中身を少し弄ります。

```c:unitTest.c
#include <CUnit/CUnit.h>
// #include <CUnit/Console.h> ★ココ
#include <CUnit/Automated.h> ★ココ

#include "add.h"

/**
 * addテストスイート
 **/
// テスト関数001
void test_add_001(void) {
	CU_ASSERT_EQUAL(add(1, 2), 3);
}

// テスト関数002
void test_add_002(void) {
	CU_ASSERT_EQUAL(add(-1, -2), -3);
}

// main関数
int main() {
CU_pSuite add_suite;

    CU_initialize_registry(); // 2.テスト構造の初期化
    add_suite = CU_add_suite("add", NULL, NULL); // 3.テストスイートの追加
    CU_add_test(add_suite, "test_001", test_add_001); // 4.テスト関数の追加
    CU_add_test(add_suite, "test_002", test_add_002); // 4.テスト関数の追加

	CU_automated_run_tests(); // ★ココ
    // CU_console_run_tests(); // 5.適切なインターフェースを使用してテストを実行 ★ココ
    CU_cleanup_registry(); // 6.テスト構造のクリーン
}

```

さっそく実行しましょう

```bash:Bash
gcc add.c unitTest.c -Wall -L/usr/local/lib -lcunit -o unitTest
./unitTest
```

実行すると、`CUnitAutomated-Results.xml`という名前のxmlファイルが吐き出されます。
これを後工程のJenkinsで利用予定です。

# CUnitドキュメント
今回の記事を書く上で使用した、CUnitのドキュメントへのリンクの一覧を貼って起きます。

- [CUnitのホームページ](http://cunit.sourceforge.net/) (CUIからでもダウンロード可)
- [CUnitのドキュメント](http://cunit.sourceforge.net/doc/index.html) こちらのページにCUnitの使用について大体のことが書いてあります。
- [CUnitのドキュメント](http://cunit.sourceforge.net/doxdocs/index.html) doxygenにて生成されたドキュメントです
- README ダウンロードしたファイルを解凍したフォルダの中に格納されています。インストール関連について書かれています。

# 次回
今回までで、何故テスト駆動で開発を進めていくのかについて説明し、xUnitによるテストを導入してきました。
これでいつでもテストを走らせる環境が整いそうです。
でも、まだ手動の箇所が残ってますね。
そうです。ビルド工程です。
次回はこの部分をCMakeによって自動化していきます。

# 参考文献
[CUnit User Guide](http://cunit.sourceforge.net/doc/index.html)
[CUnitでCプログラムの単体テストをする](https://qiita.com/muniere/items/ff9a984ed7e51eee7112)
[CUnitについての備忘録](https://qiita.com/from_chc/items/db771bef1e83fc00783a)
[gcc コンパイルオプション備忘録](https://qiita.com/seriru13/items/c2f5192615162c4c3f47#%E9%9D%99%E7%9A%84%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%82%92%E3%83%AA%E3%83%B3%E3%82%AF%E3%81%99%E3%82%8B--l)