2012年4月19日 星期四

CUnit 筆記


CUNIT是一個C語言的單元測試架構,使用者可以撰寫C語言,進行以下四種測試方式。由於筆者只需要使用Console方式測試,因此後續的編譯與使用方式都只針對Console整理
l   Automated      non-interactive with output to xml files
l   Basic        non-interactive with optional output to stdout
l   Console   interactive console mode under user control
l   Curses     interactive curses mode under user control

使用CUnit函數庫

一、直接使用CUNIT library
取得程式碼,下載連結為 http://sourceforge.net/projects/cunit/ 
Win7 64bit為例,安裝好MinGW Shell之後,執行 “configure”,接著執行 “make” 即可。編譯好的函數庫會放在 \CUnit-2.1-2\CUnit\Sources\.libs\libcunit.a。其他Unix based的作業系統,編譯方式應該也相同。
以 Linux 為例,其作法如下
1. aclocal  (if necessary)
2. autoconf (if necessary)
3. automake (if necessary)
4. chmod u+x configure (if necessary)
5. ./configure --prefix=/usr
6. make
7. sudo make install


二、測試程式直接連結 libcunit.a,即可使用
$ gcc -g test.c -lcunit

三、若編譯 library 有困難,測試程式可與CUNIT一起編譯。
1.          CUnit-2.1-2\CUnit\Headers所有檔案,加入 include path
2.          編譯時加入下列檔案
l   CUnit-2.1-2\CUnit\Sources\Automated.c
l   CUnit-2.1-2\CUnit\Sources\Basic.c
l   CUnit-2.1-2\CUnit\Sources\Console.c
l   CUnit-2.1-2\CUnit\Sources\CUError.c
l   CUnit-2.1-2\CUnit\Sources\MyMem.c
l   CUnit-2.1-2\CUnit\Sources\TestDB.c
l   CUnit-2.1-2\CUnit\Sources\TestRun.c
l   CUnit-2.1-2\CUnit\Sources\Util.c

四、測試程式與CUNIT一起編譯的可能問題 (以 Mac OSX 10.9.5為例)
以下將我在編譯程式時所遇到的問題作一整理, 
1. CUnit.h file not found
解法:rename CUnit.h.in to Cunit.h 
2. Conflicting types for 'getmouse'
問題在於我的系統內有多個 curse.h 
a. XCode default include path 為 '/usr/include/curse.h'
     Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.
 
b. GNU C default include path 為 '/opt/local/include/curses.h'
     Copyright (c) 1998-2010,2011 Free Software Foundation, Inc. 
解法:確定編譯時只採用其中一個 include path 即可解決此問題
  /usr/include/curse.h
 
 
3. forward declaration of 'struct _win_st'
參考 curses.h 如下:
#ifndef NCURSES_OPAQUE
#define NCURSES_OPAQUE 1
#endif 
#if !NCURSES_OPAQUE
struct ldat;
struct _win_st
{
// ....
}
#endif
因為 NCURSES_OPAQUE 預設值為1,導致'struct _win_st'沒有正確的定義,因此 forward declaration 找不到'struct _win_st' 
解決方式是在編譯程式時加入 '-DNCURSES_OPAQUE=0'
API用法:
所有CUnit的函數都以 “CU_”的形式出現。以下是一個簡單的使用範例:

#include "CUnit.h"
#include "Console.h"
static int TestInit(void) {return 0;}
static int TestClean(void) {return 0;}

void testAssertTrue(void)
{
  CU_ASSERT_TRUE(CU_TRUE);
  CU_ASSERT_TRUE(!CU_FALSE);

  CU_ASSERT_TRUE(!CU_TRUE);
  CU_ASSERT_TRUE(CU_FALSE);
}

void main(void)
{
    CU_pSuite pSuite;

    CU_initialize_registry();

    pSuite = CU_add_suite("TestHello", TestInit, TestClean);
    CU_add_test(pSuite, "testAssertTrue", testAssertTrue);

    CU_console_run_tests();
    CU_cleanup_registry();
}

執行結果如下:


若是使用者想要自動執行測試範例,只要置換 CU_console_run_tests()即可。
將自動測試結果導出至 Stdout, 使用 CU_basic_run_tests()


自動測試結果導出至 XML 使用 CU_automated_run_tests(),預設名稱為CUnitAutomated-Results.xml,若要更改名稱可以使用 CU_set_output_filename()設定。


上面提供了三種測試報表介面,筆者個人傾向是平常開發時使用CU_console_run_tests(),需要提供客戶報表時再改成使用CU_automated_run_tests()

參考資料:
  1. http://cunit.sourceforge.net/index.html
  2. https://netbeans.org/kb/docs/cnd/c-unit-test.html?print=yes
  3. https://trac.macports.org/ticket/21277