(圖示為Python.org 版權所有)
最近有個朋友聊起TDD (Test Driven Programming) 測試導向程式設計,測試導向的優點:
便是能減少重覆測試所需要人工測試時間,當網友若修改程式庫時,
敢對進行程式優化,也較對修改有把握,因為可利用自動測試的程式來立刻驗證。
他最常使用C來寫程式,但是使用C來寫測試函式,就算附加CPPUnit 之類,還是需要比較多時間實作。
所以筆者寫了本篇心得,使用Python 來直接對C函式庫進行測試。
本次範例包括下列:
檔案名稱 | 說明 |
test.c | 編繹為函式庫libtest.so或libtest.dll |
main.c | 編譯連結測試main() |
main.py | 用來載入測試函式庫的python 腳本檔 |
Makefile | 執行編譯及測試 |
test.c
#include <stdio.h> #define UBOUND 10 // 上限 #define LBOUND 1 // 下限 int foo(int r) { if (r > UBOUND) return UBOUND; if (r < LBOUND) return LBOUND; printf("foo(%d) executed.", r); return r; } |
main.py部分程式範例:
此腳本主要使用cdll.LoadLibrary來載入所要進行測試函式庫
from ctypes import * foolib = cdll.LoadLibrary(libname) |
接著使用下列函式來驗查超出上限、下限及正常值。
(註:為求易懂並無使用其他測試函式庫。網友們可在網上找尋到許多python 測試函式庫,來縮短開發時程。)
def verify_lbound(): p = 0 r = foolib.foo(p) return verify_ifeq(1, r, p,"case lbound") def verify_ubound(): p = 11 r = foolib.foo(p) return verify_ifeq(10, r, p, "case ubound") def verify_general(): p = 5 r = foolib.foo(p) return verify_ifeq(p, r, p, "case general") |
多平台編繹測試
在Makefile中,我們可使用uname –s 來取得使用平台的資訊,
再利用 ifeq 來實作平台不同的部分,以本次的範例而言,
平台編繹的主要在windows 使用函式庫名為.dll及執行程式副檔名為.exe,
而在Linux或Mac中,函式庫名要前綴lib,後置.so,可參考下方框紅色部分
KNAMEFULL = $(shell uname -s | sed 's/_.*//g') # cygwin on windows xp # CYGWIN_NT-5.1 KNAME = $(KNAMEFULL) ifeq ($(KNAME),CYGWIN) EXEEXT = .exe DLLEXT = .dll else EXEEXT = DLLEXT = .so endif |
編繹並執行測試:
Makefile檔案在 all: 加上 run,以用表示編繹 foo$(EXEEXT),
然後,從run程式段來看,在Linux或Mac中, export LD_LIBRARY_PATH=.
來通知載入程式,函式庫在目前目錄中。
緊接著,執行 foo$(EXEEXT) ,驗證二進位連結無誤,
再執行python 腳本測試,如有任何錯誤產生,顯示make失敗錯誤。
all: run … run: foo$(EXEEXT) @ export LD_LIBRARY_PATH=.; ./$^ ; \ if [ $$? -eq 3 ]; then \ echo "Binary linking passed" ; \ python main.py $(LIBNAME)$(DLLEXT) ; \ if [ $$? -ne 0 ] ; then \ exit 1; \ fi \ else \ echo "Binary link failed" ; \ fi |
測試結果:
$ make cc -c -o main.o main.c -Wall cc -c -o test.o test.c -Wall cc -o libtest.so -shared test.o cc -o foo main.o -ltest -L. foo(3) executed.Binary linking passed case ubound:verified return value(10) from test.foo(11) [Passed] case lbound:verified return value(1) from test.foo(0) [Passed] foo(5) executed.case general:verified return value(5) from test.foo(5) [Passed] total/passed cases: 3/3 Python load libtest.so [Passed] |
下列平台經過測試無誤:
- Ubuntu 10.10: Python 2.6.6
- Win XP SP3: CYGWIN_NT-5.1 + Python 2.6.5
- Snowleopard 10.6.8: Xcode4.0.2+Python 2.6.1
本次所有範例可從源碼GitHub使用git下載,歡迎交流經驗或提供建議。
沒有留言:
張貼留言