(圖示為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下載,歡迎交流經驗或提供建議。