흔히 TDD 라고 하면, C나 JAVA 를 떠올린다. 그만큼 오브젝트 단위로 프로그래밍이 되기 때문에 TDD 를 하기 수월하고 또한 TDD 지원 툴도 많다.
하지만, 임베디드 프로그래밍에서는 아직도 C 언어를 많이 사용하는 관계로 실상 TDD 를 써먹을 수 있는 기회가 거의 없다.
지금까지 애자일 프로그래밍 방법론(XP 포함)에 관한 책을 5 권 이상 읽어본 나로써는 그렇게 좋다는 TDD 를 언젠가는 프로젝트에 사용해보고 싶었다.
C 언어에서도 TDD 를 할 수 없을까 찾던 중에 CUnit 이라는 툴을 알게 되었다.
여기서는 CUnit 에 대한 모든 것에 대해서 설명한다. http://blog.naver.com/yuzico/130017038508 를 참고했다.
====== 준비운동 하기 ======
CUnit 은 http://cunit.sourceforge.net 에서 다운로드 받을 수 있다. 윈도우용과 리눅스용 모두 지원한다.
참고로 여기서는 redhat 9 을 기준으로 살펴볼 것이다. tar 소스 파일로 컴파일 중에 라이브러리 버전 문제로 인한 에러가 발생했다.
이런 이유로 rpm 으로 설치했다. 현재 최신 버전은 2.1.0 이다.
제대로 설치되었는지를 확인하기 위해 다음을 실행한다.
<code text>
#ls /usr/local/doc
#ls /usr/local/include/
#ls /usr/local/lib/
#ls /usr/local/man/man3/
#ls /usr/local/share/
</code>
CUnit 관련 파일들이 있다면, 제대로 설치된 것이다.
====== CUnit 의 구조 ======
설치한 파일 중에서 실제로 CUnit 에서 사용하는 것은 인클루드 파일과 라이브러리 파일이다. 일반적으로 'CUnit/CUnit.h' 를 인클루드하고, 라이브러리를 링크하면 된다. 이것에 의해서 CUnit 에 정의된 여러가지 매크로/함수/정수들을 사용할 수 있다.
사용하는 순서는 다음과 같다.
- 테스트 케이스 함수를 작성한다.
- 필요에 따라서 셋업함수, 클린 업 함수를 준비한다.
- 테스트레지스트리를 작성/초기화한다. 이때 'CU_initialize_registry()' 라는 함수를 호출한다.
- 테스트시트를 테스트레지스트리에 추가한다. 이때 'CU_add_suite()' 라는 함수를 이용한다.
- 테스트케이스를 테스트시트에 추가한다. 이때 'CU_add_test()' 라는 함수를 이용한다.
- 테스트를 실행한다. 예를 들면, 'CU_console_run_tests()' 라는 함수를 호출한다.
- 테스트레지스트리를 삭제한다. 'CU_cleanup_registry()' 라는 함수를 호출한다.
====== 사용 하기 ======
예제를 통해, 사용법을 설명하겠다.
<code text>
#include <CUnit/CUnit.h> // CUnit 을 사용하기 위한 인클루드
#include <CUnit/Console.h> // CUnit 을 사용하기 위한 인클루드

void sort(int array[], int num);
void test_1(void); // 테스트 케이스 선언
void test_2(void);
void test_3(void);
void test_4(void);
void test_5(void);

int main(){
CU_pSuite sort_suite;

CU_initialize_registry();
sort_suite = CU_add_suite("Sort", NULL, NULL);
CU_add_test(sort_suite, "test_01", test_1); // 테스트 케이스 등록
CU_add_test(sort_suite, "test_02", test_2);
CU_add_test(sort_suite, "test_03", test_3);
CU_add_test(sort_suite, "test_04", test_4);
CU_add_test(sort_suite, "test_05", test_5);

CU_console_run_tests();
CU_cleanup_registry();

return(0);
}


void sort(int array[], int num){
int i;
int j;
int val;

for(i=0; i<(num-1); i++){
for(j=(num-1); j>i; j--){
if(array[j-1] > array[j]){
val = array[j];
array[j] = array[j-1];
array[j-1] = val;
}
}
}
}

void test_1(void){
int array[] = {3};
sort(array, 1);
CU_ASSERT(array[0] == 3);
}

void test_2(void){
int array[] = {11,7,5,3,2};

sort(array, 5);
CU_ASSERT(array[0] == 2);
CU_ASSERT(array[1] == 3);
CU_ASSERT(array[2] == 5);
CU_ASSERT(array[3] == 7);
CU_ASSERT(array[4] == 11);
}

void test_3(void){
int array[] = {7,11,3,2,5};

sort(array, 5);
CU_ASSERT(array[0] ==2);
CU_ASSERT(array[1] ==3);
CU_ASSERT(array[2] ==5);
CU_ASSERT(array[3] ==7);
CU_ASSERT(array[4] ==11);
}

void test_4(void){
int array[] = {10,9,8,7,6,5,4,3,2,1};

sort(array,10);


CU_ASSERT(array[0] ==1);
CU_ASSERT(array[1] ==2);
CU_ASSERT(array[2] ==3);
CU_ASSERT(array[3] ==4);
CU_ASSERT(array[4] ==5);
CU_ASSERT(array[5] ==6);
CU_ASSERT(array[6] ==7);
CU_ASSERT(array[7] ==8);
CU_ASSERT(array[8] ==9);
CU_ASSERT(array[9] ==10);
}

void test_5(void){
int array[] = {2,9,3,6,10,5,8,4,1,7};

sort(array, 10);

CU_ASSERT(array[0] ==1);
CU_ASSERT(array[1] ==2);
CU_ASSERT(array[2] ==3);
CU_ASSERT(array[3] ==4);
CU_ASSERT(array[4] ==5);
CU_ASSERT(array[5] ==6);
CU_ASSERT(array[6] ==7);
CU_ASSERT(array[7] ==8);
CU_ASSERT(array[8] ==9);
CU_ASSERT(array[9] ==10);
}
</code>
컴파일 시에는 cunit 관련 라이브러리를 지정해야 한다.
<code text>
#gcc a.c -Wall -L /usr/local/lib -lcunit
</code>
이제 실행해보자!
<code text>
#./a.out


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


*************** CUNIT CONSOLE - MAIN MENU ***********************
(R)un all, (S)elect suite, (L)ist suites, Show (F)ailures, (Q)uit
Enter Command :
</code>
'r' 을 입력한다.
<code text>
Running Suite : Sort
Running test : test_01
Running test : test_02
Running test : test_03
Running test : test_04
Running test : test_05

--Run Summary: Type Total Ran Passed Failed
suites 1 1 n/a 0 // suites 1 개 중에 1 개가 pass 되었다
tests 5 5 5 0 // 총 5 개의 테스트 중에 5 개가 pass 되었다
asserts 31 31 31 0 // 총 31 중에 31 개가 pass 되었다

*************** CUNIT CONSOLE - MAIN MENU ***********************
(R)un all, (S)elect suite, (L)ist suites, Show (F)ailures, (Q)uit
</code>
총 5 가지의 테스트 케이스를 수행했고, 모두 테스트를 통과한 것으로 나왔다.
이제 코드를 수정해서, 오류를 임의적으로 만들어보겠다.
<code text>
void sort(int array[], int num){
int i;
int j;
int val;

for(i=0; i<(num-1); i++){
for(j=(num-1); j>i; j--){
if(array[j-1] > array[j]){
val = array[j];
array[j] = array[j]; // 코드수정
array[j-1] = val;
}
}
}
}
</code>
다시 컴파일해서 실행해보자. 'r' 을 입력한다.
<code text>
Running Suite : Sort
Running test : test_01
Running test : test_02
Running test : test_03
Running test : test_04
Running test : test_05

--Run Summary: Type Total Ran Passed Failed
suites 1 1 n/a 0 // suites 1 개 중에 1 개가 실패
tests 5 5 1 4 // 총 5 개의 테스트 중에 4 개가 실패
asserts 31 31 5 26 // 총 31 중에 26 개가 실패

*************** CUNIT CONSOLE - MAIN MENU ***********************
(R)un all, (S)elect suite, (L)ist suites, Show (F)ailures, (Q)uit
</code>
여기서 'f' 를 입력하면, 실패한 내용이 리스트 된다. 어떤 파일의 어떤 장소에 있는 어떤 assert 가 실패하고 있는지 알 수 있다.
's' 를 입력하면 테스트 레지스트리 계층으로부터 테스트시트의 계층과 테스트케이스의 계층을 선택적으로 구동하고 따라 내려 갈 수 있기 때문에, 실패의 개수가 많을 때에는, 특정 테스트시트/테스트케이스만을 체크할 수 있다.
계층을 내려갔을 때, '(M)ove up' 라고 하는 명령어가 나타나기 때문에, 'm' 을 입력하면 상위 계층으로 돌아올 수 있다.
====== ASSERT 매크로 ======
CUnit 에서 정의하고 있는 assert 매크로는 테스트가 성공했는지 실패했는지를 판정 혹은 등록한다.
목록은 /usr/local/include/CUnit/CUnit.h 에 정의되어 있다. 각각 인수의 종류에 따라 매크로가 준비되어 있다.
상황에 따라 적절한 것을 사용하면 된다.
CU_ASSERT(), CU_TEST(), CU_ASSERT_TRUE(), CU_ASSERT_FALSE() 은 인수가 불리언 타입이기 때문에 유용하게 쓰인다.
그 외에 CU_ASSERT_EQUAL() 등은 인수가 2 개 이상 필요하며, 인수의 타입 또한 제한되어 있으므로, 적절한 매크로의 사용이 중요하다.
목록을 유심히 보면, 각 종류의 매크로마다 끝에 _FATAL 로 끝나는 것이 있는 것을 알 수 있다. 이것을 사용할 경우, 그 매크로가 Fail 로 판정되면, 해당 테스트 시트가 종료하게 된다. 테스트 대상 함수가 있고 그에 대한 테스트케이스가 있을 경우, 그 FATAL 테스트 케이스가 실패하면 다른 테스트케이스냐 테스트시트 또한 중단된다.
assert 를 매크로 라고 적어 놓은 것처럼, 이것들은 함수가 아니라 매크로이다. assert 들의 정의를 보면, 모든 assert 들은 CU_assertimplementation(...) 이라는 함수를 호출하고 있는 것을 알 수 있다.
<code text>
#define CU_TRUE 1
#define CU_FALSE 0
#define CU_ASSERT(value)
{ CU_assertlmplementation((value), __LINE__, #value, __FILE__, "", CU_FALSE); }
#define CU_ASSERT_FATAL(value)
{ CU_assertlmplementation((value), __LINE__, #value, __FILE__, "", CU_TRUE); }
</code>
C 프리프로세서에서 처리되고, __LINE__ 을 통하여 소스코드의 행 번호, __FILE__ 을 통하여 해당 파일 이름을 가지게 되며, # 으로 처리된 매크로 파라미터의 내용은 문자열로 바뀌어 준비된다. 즉, CU_assertlmplementation() 이라는 함수는 이러한 정보를 건내받아 테스트가 fail 했을 때 어느 파일의 몇번째 행의 assert 에서 발생했고 그 내용은 무엇인지를 알려줄 수 있게 되는 것이다.
이런 내용은 매크로를 사용하는 데 도움이 된다.
====== 테스트 레지스트리 ======
지금까지의 CUnit 설명을 보면, 테스트 레지스트리는 1 개만 있어야 되는 것처럼 보인다. 하지만, 실제로는 여러 개를 작성할 수 있다. 그렇지만 CUnit 의 함수는 테스트 레지스트리가 복수로 구성되는 것에 대해 고려하지 않는다.
동작 중인 하나의 테스트 레지스트리(액티브 테스트 레지스트리)만을 대상으로 구동된다. 따라서, 만약 여러개의 테스트 레지스트리를 작성하여 테스트 환경을 구축한다면, 몇 개의 어떠한 테스트 레지스트리가 있고, 어떤 것에 대하여 어떻게 조작하고 구동해야하는지에 대한 관리 책임은 전적으로 CUnit 을 사용하는 개발자에게 있다.
===== 테스트 레지스트리의 초기화 =====

#include <CUnit/CUnit.h>
#include <CUnit/Basic.h>
//#include <CUnit/Console.h>  // CU_basic_run_tests() 를 사용할 때 인클루드
 
void sort(int array[], int num);
void test_1(void);
void test_2(void);
void test_3(void);
void test_4(void);
void test_5(void);
 
int main(){
 
CU_pTestRegistry test_registry1;   // 테스트레지스트리 1
CU_pTestRegistry test_registry2;   // 테스트레지스트리 2
CU_pSuite sort_suite1;         // 테스트 시트 1
CU_pSuite sort_suite2;         // 테스트 시트 2
 
CU_initialize_registry();
sort_suite1 = CU_add_suite("Sort1", NULL, NULL);
CU_add_test(sort_suite1, "test_01", test_1);
CU_add_test(sort_suite1, "test_02", test_2);
 
CU_basic_run_tests();    // 여기서 일단의 테스트를 실행
 
// 테스트 레지스트리를 작성해 액티브를 교체
test_registry2 = CU_create_new_registry();
test_registry1 = CU_set_registry(test_registry2);
 
sort_suite2 = CU_add_suite("Sort2", NULL, NULL);
 
CU_add_test(sort_suite2, "test_03", test_3);
CU_add_test(sort_suite2, "test_04", test_4);
CU_add_test(sort_suite2, "test_05", test_5);
 
CU_basic_set_mode(CU_BRM_NORMAL);  // 요약과 에러만을 표시하도록 설정
 
CU_basic_run_tests();            // 여기서 2 번째의 테스트레지스트리 실행
CU_cleanup_registry();           // 현재의 액티브는 test_registry2
 
CU_destroy_existing_registry(&test_registry1);    // 레지스트리 파기
 
return(0);
}
 
 
void sort(int array[], int num){
int i;
int j;
int val;
 
for(i=0; i<(num-1); i++){
for(j=(num-1); j>i; j--){
if(array[j-1] > array[j]){
val = array[j];
array[j] = array[j];     // 코드 수정
array[j-1] = val;
}
}
}
}
 
void test_1(void){
int array[] = {3};
sort(array, 1);
CU_ASSERT(array[0] == 3);
}
 
void test_2(void){
int array[] = {11,7,5,3,2};
 
sort(array, 5);
CU_ASSERT(array[0] == 2);
CU_ASSERT(array[1] == 3);
CU_ASSERT(array[2] == 5);
CU_ASSERT(array[3] == 7);
CU_ASSERT(array[4] == 11);
}
 
void test_3(void){
int array[] = {7,11,3,2,5};
 
sort(array, 5);
CU_ASSERT(array[0] ==2);
CU_ASSERT(array[1] ==3);
CU_ASSERT(array[2] ==5);
CU_ASSERT(array[3] ==7);
CU_ASSERT(array[4] ==11);
}
 
void test_4(void){
int array[] = {10,9,8,7,6,5,4,3,2,1};
 
sort(array,10);
 
 
CU_ASSERT(array[0] ==1);
CU_ASSERT(array[1] ==2);
CU_ASSERT(array[2] ==3);
CU_ASSERT(array[3] ==4);
CU_ASSERT(array[4] ==5);
CU_ASSERT(array[5] ==6);
CU_ASSERT(array[6] ==7);
CU_ASSERT(array[7] ==8);
CU_ASSERT(array[8] ==9);
CU_ASSERT(array[9] ==10);
}
 
void test_5(void){
int array[] = {2,9,3,6,10,5,8,4,1,7};
 
sort(array, 10);
 
CU_ASSERT(array[0] ==1);
CU_ASSERT(array[1] ==2);
CU_ASSERT(array[2] ==3);
CU_ASSERT(array[3] ==4);
CU_ASSERT(array[4] ==5);
CU_ASSERT(array[5] ==6);
CU_ASSERT(array[6] ==7);
CU_ASSERT(array[7] ==8);
CU_ASSERT(array[8] ==9);
CU_ASSERT(array[9] ==10);
}


컴파일 후에 실행하면, 다음과 같다.

     CUnit - A Unit testing framework for C - Version 2.1-0
     http://cunit.sourceforge.net/
 
 
Suite Sort1, Test test_02 had failures:
    1. d.c:73  - array[1] == 3
    2. d.c:74  - array[2] == 5
    3. d.c:75  - array[3] == 7
    4. d.c:76  - array[4] == 11
 
--Run Summary: Type      Total     Ran  Passed  Failed
               suites        1       1     n/a       0
               tests         2       2       1       1
               asserts       6       6       2       4
 
 
     CUnit - A Unit testing framework for C - Version 2.1-0
     http://cunit.sourceforge.net/
 
 
Suite Sort2, Test test_03 had failures:
    1. d.c:84  - array[1] ==3
    2. d.c:85  - array[2] ==5
    3. d.c:86  - array[3] ==7
    4. d.c:87  - array[4] ==11
Suite Sort2, Test test_04 had failures:
    1. d.c:97  - array[1] ==2
    2. d.c:98  - array[2] ==3
    3. d.c:99  - array[3] ==4
    4. d.c:100  - array[4] ==5
    5. d.c:101  - array[5] ==6
    6. d.c:102  - array[6] ==7
    7. d.c:103  - array[7] ==8
    8. d.c:104  - array[8] ==9
    9. d.c:105  - array[9] ==10
Suite Sort2, Test test_05 had failures:
    1. d.c:114  - array[1] ==2
    2. d.c:115  - array[2] ==3
    3. d.c:116  - array[3] ==4
    4. d.c:117  - array[4] ==5
    5. d.c:118  - array[5] ==6
    6. d.c:119  - array[6] ==7
    7. d.c:120  - array[7] ==8
    8. d.c:121  - array[8] ==9
    9. d.c:122  - array[9] ==10
 
--Run Summary: Type      Total     Ran  Passed  Failed
               suites        1       1     n/a       0
               tests         3       3       0       3
               asserts      25      25       3      22


위의 결과를 통해, 2 개의 테스트 레지스트리가 실행되는 것을 볼 수 있다.
====== 테스트 시트 ======
앞의 예제에서 보인 것처럼, 액티브 테스트 레지스트리에 테스트 시트를 추가하는 함수는 CU_add_suite() 이다.

| 함수 | CU_pSuite CU_add_suite(const char* strName, CU_InitializeFunc pInit, CU_CleanupFunc pClean) |
| 설명 | 첫번째 인수로 나타나는 이름, 두번째 인수로 나타나는 초기화 함수, 세번째 인수로 나타나는 클린 업 함수를 가지는 테스트 시트 영역을 작성하여, 액티브 테스트 레지스트리에 등록한다. 리턴 값은 테스트시트 영역의 포인터이다. 에러가 발생했을 경우는 NULL 을 돌려준다. 이 함수는 호출전에 테스트레지스트리가 있어야 한다 |

첫번째 인수인 이름은 테스트레지스트리에 같은 이름이 있으면 안됩니다. 초기화 함수와 클린 업 함수는 해당 테스트시트의 실행 전과 실행 후에 자동적으로 호출되는 함수입니다. 이 함수들은 인수가 없으며, 성공적으로 끝났을 때는 0 을 돌려줍니다. (처리가 실패했을 경우에는 0 이외의 값을 돌려줍니다.) 초기화함수/클린업 함수가 불필요하면 NULL 을 지정합니다.
테스트 시트 영역의 포인터가 리턴되므로, 데이터 형식(구조체)에 대해 알아 두면 좋을 것입니다.

typedef struct CU_Suite{
char* pName;
CU_pTest pTest;
CU_InitializeFunc pInitializeFunc;
CI_CleanupFunc pCleanupFunc;
unsigned int uiNumberOfTests;
struct CU_Suite* pNext;
struct CU_Suite* pPrev;
}CU_Suite;
typedef CU_Suite* CU_pSuite;


구조체는 테스트시트의 이름, 테스트케이스 리스트의 맨 앞쪽 포인터, 초기화 함수와 클린 업 함수, 테스트케이스의 수를 관리하고 있다. 마지막 두개의 요소는 리스트의 요소라는 걸 알 수 있다.
함수 CU_add_suite() 는 테스트시트 영역의 포인터를 돌려주므로, 실패 여부는 리턴 값이 NULL 인지를 확인하는 것으로 알아볼 수 있다. 혹시 에러를 상세히 알고 싶다면 CUnit 의 에러 관리의 구조를 이용하면 된다.
예제를 통해 사용법을 알아보자!

#include <CUnit/CUnit.h>
#include <CUnit/Console.h>
#include <CUnit/Basic.h>
 
void sort(int array[], int num);
void test_1(void);
void test_2(void);
void test_3(void);
void test_4(void);
void test_5(void);
 
int main(){
 
CU_ErrorCode errorCode;
 
// 테스트케이스의 배열
CU_TestInfo test_array1[] = {
{"Test_1", test_1},
{"Test_2", test_2},
{"Test_3", test_3},
{"Test_4", test_4},
{"Test_5", test_5},
CU_TEST_INFO_NULL
};
 
// 테스트시트의 배열
CU_SuiteInfo suites_array1[] = {
{"Suite_1", NULL, NULL, test_array1},
CU_SUITE_INFO_NULL
};
 
 
CU_initialize_registry();
 
errorCode = CU_register_suites(suites_array1);   // 여기서 등록
 
CU_console_run_tests();
CU_cleanup_registry();
 
return(0);
}
 
 
void sort(int array[], int num){
int i;
int j;
int val;
 
for(i=0; i<(num-1); i++){
for(j=(num-1); j>i; j--){
if(array[j-1] > array[j]){
val = array[j];
array[j] = array[j];
array[j-1] = val;
}
}
}
}
 
void test_1(void){
int array[] = {3};
sort(array, 1);
CU_ASSERT(array[0] == 3);
}
 
void test_2(void){
int array[] = {11,7,5,3,2};
 
sort(array, 5);
CU_ASSERT(array[0] == 2);
CU_ASSERT(array[1] == 3);
CU_ASSERT(array[2] == 5);
CU_ASSERT(array[3] == 7);
CU_ASSERT(array[4] == 11);
}
 
void test_3(void){
int array[] = {7,11,3,2,5};
 
sort(array, 5);
CU_ASSERT(array[0] ==2);
CU_ASSERT(array[1] ==3);
CU_ASSERT(array[2] ==5);
CU_ASSERT(array[3] ==7);
CU_ASSERT(array[4] ==11);
}
 
void test_4(void){
int array[] = {10,9,8,7,6,5,4,3,2,1};
 
sort(array,10);
 
 
CU_ASSERT(array[0] ==1);
CU_ASSERT(array[1] ==2);
CU_ASSERT(array[2] ==3);
CU_ASSERT(array[3] ==4);
CU_ASSERT(array[4] ==5);
CU_ASSERT(array[5] ==6);
CU_ASSERT(array[6] ==7);
CU_ASSERT(array[7] ==8);
CU_ASSERT(array[8] ==9);
CU_ASSERT(array[9] ==10);
}
 
void test_5(void){
int array[] = {2,9,3,6,10,5,8,4,1,7};
 
sort(array, 10);
 
CU_ASSERT(array[0] ==1);
CU_ASSERT(array[1] ==2);
CU_ASSERT(array[2] ==3);
CU_ASSERT(array[3] ==4);
CU_ASSERT(array[4] ==5);
CU_ASSERT(array[5] ==6);
CU_ASSERT(array[6] ==7);
CU_ASSERT(array[7] ==8);
CU_ASSERT(array[8] ==9);
CU_ASSERT(array[9] ==10);
}


컴파일 후에 실행해보면, 예전과 동일하게 동작하는 것을 확인할 수 있다.
====== 테스트의 실행 ======
테스트를 실행하는 방법으로 콘솔 상에서 인터랙티브하게 사용하는 방법(CU_console_run_tests()를 사용)과 배치처리하는 방법(CU_basic_run_tests()를 사용)을 해 보았다.
CUnit 에서는 이들을 포함하여 모두 4 개의 실행모드가 있다.
===== Automated 모드 =====
배치적으로 처리하는 모드이다. 출력은 XML 형식의 파일이다. Unit/Automated.h 를 인클루드 한다. 모든 플랫폼에서 사용 가능하다.
===== Basic 모드 =====
배치적으로 처리하는 모드이다. 출력은 표준 출력이다. CUnit/Basic.h 를 인클루드 한다. 모든 플랫폼에서 사용가능하다.
===== Console 모드 =====
인터랙티브한 조작을 받아들이는 모드이다. 출력은 표준 출력이다. CUnit/Console.h 를 인클루드 한다. 모든 플랫폼에서 사용가능하다.
===== Curses 모드 =====
인터랙티브한 조작을 받아들이는 모드이다. 표준 출력과는 달리, 화면밖으로 표시되는 정보도, 커서 키 스크롤을 통해 확인할 수 있다. CUnit/CUCurses.h 를 인클루드하고, curses 라이브러리의 링크도 필요하다. UNIX 계열만 사용가능하다.
====== 에러 처리 ======
===== 에러 상태의 취득 =====
테스트시트에서 살펴보았듯이 에러상태를 얻어오는 함수가 있다. 여기에는 에러코드를 리턴하는 함수와 에러 메세지 문자열을 리턴하는 함수 2 가지가 있다.

| 함수 | CU_ErrorCode CU_get_error(void) |
| 설명 | 에러코드를 리턴한다 |

| 함수 | const char* CU_get_error_msg(void) |
| 설명 | 에러 메세지 문자열을 리턴한다 |

에러 코드는 열거형으로써 CUnit/CUError.h 에 정의되어 있다. 이 파일은 CUnit/CUnit.h 에서도 호출되고 있으므로, 파일 인클루드에 상관없이 이용 가능하다. 다음은 에러코드 목록이다.

| CUE_SUCCESS | 성공(에러 없음) |
| CUE_NOMEMORY | 메모리 할당 실패 |
| CUE_NOREGISTRY | 테스트 레지스트리 초기화안됨 |
| CUE_REGISTRY_EXISTS | CU_cleanup_registry()를 실행하지 않고 CU_set_registry() 를 실행 |
===== 에러 발생시의 행동 =====
에러가 발생해도 CUnit 은 계속 동작한다. 하지만, 에러가 발생시 테스트를 멈추거나 경우에 따라서는 어플리케이션을 종료하고 싶은 경우 다음의 함수를 사용한다.

| 함수 | void CU_set_error_action(CU_ErrorAction action) |
| 설명 | 에러 발생시의 행동을 설정한다 |

| 함수 | CU_ErrorAction CU_get_error_action(void) |
| 설명 | 설정된 에러 발생시의 행동을 리턴한다 |

CU_ErrorAction 이라는 타입은 열거형이다. 다음의 값을 이용할 수 있다.

- CUEA_IGNORE : 에러가 발생해도, 계속 진행한다.
- CUEA_FAIL : 에러가 발생하면 테스트를 멈춘다.
- CUEA_ABORT : 에러가 발생하면 어플리케이션에서 빠져 나온다. (exit() 를 실행)

====== 마치면서 ======
더 자세한 내용은 cunit.zip 에서 볼 수 있다.