锘??xml version="1.0" encoding="utf-8" standalone="yes"?>
]]>
]]>
[python] view plaincopy
- def logged(func):
- def with_logging(*args, **kwargs):
- print func.__name__ + " was called"
- return func(*args, **kwargs)
- return with_logging
then when you say
[python] view plaincopy
- @logged
- def f(x):
- """does some math"""
- return x + x * x
it's exactly the same as saying
[python] view plaincopy
- def f(x):
- """does some math"""
- return x + x * x
- f = logged(f)
and your function f is replaced with the function with_logging. Unfortunately, this means that if you then say
[python] view plaincopy
- print f.__name__
it will print with_logging
because that's the name of your new function. In fact, if you look at the docstring for f, it will be blank because with_logging has no docstring, and so the docstring you wrote won't be there anymore. Also, if you look at the pydoc result for that function, it won't be listed as taking one argument x
; instead it'll be listed as taking *args
and **kwargs
because that's what with_logging takes.
If using a decorator always meant losing this information about a function, it would be a serious problem. That's why we have functools.wraps
. This takes a function used in a decorator and adds the functionality of copying over the function name, docstring, arguments list, etc. And since wraps
is itself a decorator, the following code does the correct thing:
[python] view plaincopy
- from functools import wraps
- def logged(func):
- @wraps(func)
- def with_logging(*args, **kwargs):
- print func.__name__ + " was called"
- return func(*args, **kwargs)
- return with_logging
- @logged
- def f(x):
- """does some math"""
- return x + x * x
- print f.__name__ # prints 'f'
- print f.__doc__ # prints 'does some math'
杞嚜http://blog.csdn.net/wanghai__/article/details/7078792
鍦ㄩ氬父鎯呭喌涓嬶紝鍏變韓搴撻兘鏄氳繃浣跨敤闄勫姞閫夐」 -fpic 鎴?nbsp;-fPIC 榪涜緙栬瘧錛屼粠鐩爣浠g爜浜х敓浣嶇疆鏃犲叧鐨勪唬鐮侊紙Position Independent Code錛孭IC錛夛紝浣跨敤 -shared閫夐」灝嗙洰鏍囦唬鐮佹斁榪涘叡浜洰鏍囧簱涓備綅緗棤鍏充唬鐮侀渶瑕佽兘澶熻鍔犺澆鍒頒笉鍚岃繘紼嬬殑涓嶅悓鍦板潃錛屽茍涓旇兘寰椾互姝g‘鐨勬墽琛岋紝鏁呭叾浠g爜瑕佺粡榪囩壒鍒殑緙栬瘧澶勭悊錛氫綅緗棤鍏充唬鐮侊紙PIC錛夊甯擱噺鍜屽嚱鏁板叆鍙e湴鍧鐨勬搷浣滈兘鏄噰鐢ㄥ熀浜庡熀瀵勫瓨鍣紙base register錛塀ASE+ 鍋忕Щ閲忕殑鐩稿鍦板潃鐨勫鍧鏂瑰紡銆傚嵆浣跨▼搴忚瑁呰澆鍒板唴瀛樹腑鐨勪笉鍚屽湴鍧錛屽嵆 BASE 鍊間笉鍚岋紝鑰屽亸縐婚噺鏄笉鍙樼殑錛屾墍浠ョ▼搴忎粛鐒跺彲浠ユ壘鍒版紜殑鍏ュ彛鍦板潃鎴栬呭父閲忋?/p>
鐒惰岋紝褰撳簲鐢ㄧ▼搴忛摼鎺ヤ簡澶氫釜鍏變韓搴擄紝濡傛灉鍦ㄨ繖浜涘叡浜簱涓紝瀛樺湪鐩稿悓浣滅敤鍩熻寖鍥寸殑鍚屽悕闈欐佹垚鍛樺彉閲忔垨鑰呭悓鍚?( 闈為潤鎬?) 鍏ㄥ眬鍙橀噺錛岄偅涔堝綋紼嬪簭璁塊棶瀹岄潤鎬佹垚鍛樺彉閲忔垨鍏ㄥ眬鍙橀噺緇撴潫鏋愭瀯鏃訛紝鐢變簬鏌愬唴瀛樺潡鐨?double free 浼氬鑷?core dump錛岃繖鏄敱浜?Linux 緙栬瘧鍣ㄧ殑緙洪櫡閫犳垚鐨勩?/p>
璇ラ棶棰樻簮浜庣瑪鑰呮墍浠庝簨鐨勫紑鍙戦」鐩細IBM Tivoli Workload Scheduler (TWS) LoadLeveler銆?strong>LoadLeveler鏄?nbsp;IBM鍦ㄩ珮鎬ц兘璁$畻錛?strong>High Performance Computing錛孒PC錛夐鍩熺殑涓嬈句綔涓氳皟搴﹁蔣浠躲傚畠涓昏鍒嗕負涓や釜澶х殑妯″潡錛屽垎鍒槸璋冨害妯″潡錛坰cheduler錛夊拰璧勬簮綆$悊妯″潡錛坮esource manger錛夈?涓や釜妯″潡涓垎鍒惈鏈夊叧浜庨厤緗鐞嗗姛鑳界殑鍏變韓搴擄紝鐢變簬鏌愪簺閰嶇疆綆$悊閫夐」涓轟袱妯″潡鎵鍏卞悓閲囩敤錛屾墍浠ヤ袱妯″潡涔嬮棿鍏變韓浜嗛儴鍒嗘簮鏂囦歡浠g爜錛屽叾涓寘鍚湁鍚屽悕鐨勭被闈欐佹垚鍛樸?/p>
鍙互閫氳繃浠ヤ笅綆鍗曠殑妯″瀷榪涜鎻忚堪錛?/p>
鍥?1. 搴旂敤鍦烘櫙
瀵瑰簲鐨勫悇妯″潡浠g爜鐗囨濡備笅鍥炬墍紺猴細
鍏朵腑錛宼est.c 鏄富紼嬪簭錛屽寘鍚湁涓や釜澶存枃浠訛細api1.h 涓?api2.h錛涘ご鏂囦歡 api1.h 鍖呭惈澶存枃浠?lib1/lib.h 鍜屼竴鍔熻兘鍑芥暟 func_api1()錛宎pi2.h 鍖呭惈澶存枃浠?lib2/lib.h 鍜屼竴鍔熻兘鍑芥暟 func_api2()錛涚洰褰?lib1 鍜?lib2 涓嬬殑婧愭枃浠跺垎鍒紪璇戠敓鎴愬叡浜簱 lib1.so 鍜?lib2.so銆傚悓鏃訛紝澶存枃浠?lib1/lib.h 涓?lib2/lib.h 閾炬帴鍒板悓涓鍏變韓鏂囦歡 lib.h銆傚湪鏂囦歡 lib.h 涓畾涔夋湁涓闈欐佹垚鍛樺彉閲?#8220;static std::vector<int> vec_int”銆?/p>
鍔熻兘鍑芥暟涓庡悇闈欐佹垚鍛樺嚱鏁頒唬鐮佹竻鍗?/span>
鍔熻兘鍑芥暟 func_api1() 涓?func_api2() 鐨勫疄鐜扮被浼鹼紝閫氳繃璋冪敤闈欐佹垚鍛樺嚱鏁拌揪鍒拌闂潤鎬佹垚鍛樺彉閲?nbsp;vec_int鐨勭洰鐨勶細
void func_api1(int i) { printf("%s.\n", __FILE__); A::set(i); A::print(); return; } |
闈欐佹垚鍛樺嚱鏁?A::set() 涓?A::print() 鐨勫疄鐜板涓嬶細
void A::set(int num) { vec_int.clear(); for (int i = 0; i < num; i++) { vec_int.push_back(i); } return; } |
void A::print() { for (int i = 0; i < vec_int.size(); i++) { printf("vec_int[%d] = %d, addr: %p.\n", i, vec_int[i], &vec_int[i]); } printf("vec_int addr: %p.\n", &vec_int); return; } |
A::set() 瀵歸潤鎬佹垚鍛?nbsp;vec_int榪涜璧嬪兼搷浣滐紝鑰?A::print() 鍒欐墦鍗板叾涓殑鍊間笌褰撳墠欏圭殑鍐呭瓨鍦板潃銆?/p>
濡傛灉涓や釜鍏變韓搴撴槸閫氳繃閫夐」 -fpic鎴?nbsp;-fPIC緙栬瘧鐨勮瘽錛岃繍琛岀▼搴?test錛岃緭鍑哄涓嬶細
$ export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH $ g++ -g -o lib1.so -fPIC-rdynamic -shared lib1/lib.c $ g++ -g -o lib2.so -fPIC-rdynamic -shared lib2/lib.c $ g++ -g -o test -L./ -l1 -l2 test.c $ ./test api1.h. vec_int[0] = 0, addr: 0x9cbf028. vec_int[1] = 1, addr: 0x9cbf02c. vec_int[2] = 2, addr: 0x9cbf030. vec_int[3] = 3, addr: 0x9cbf034. vec_int addr: 0xe89228. *** glibc detected *** ./test: double free or corruption (fasttop): 0x09cbf028*** ======= Backtrace:========= /lib/libc.so.6[0x2b2b16] /lib/libc.so.6(cfree+0x90)[0x2b6030] /usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0x5d1731] ./lib1.so(_ZN9__gnu_cxx13new_allocatorIiE10deallocateEPij+0x1d)[0xe88417] ./lib1.so(_ZNSt12_Vector_baseIiSaIiEE13_M_deallocateEPij+0x33)[0xe88451] ./lib1.so(_ZNSt12_Vector_baseIiSaIiEED2Ev+0x42)[0xe8849a] ./lib1.so(_ZNSt6vectorIiSaIiEED1Ev+0x60)[0xe8850c] ./lib2.so[0x961d6c] /lib/libc.so.6(__cxa_finalize+0xa9)[0x275c79] ./lib2.so[0x961c34] ./lib2.so[0x962d3c] /lib/ld-linux.so.2[0x23a7de] /lib/libc.so.6(exit+0xe9)[0x2759c9] /lib/libc.so.6(__libc_start_main+0xe4)[0x25fdf4] ./test(__gxx_personality_v0+0x45)[0x80484c1] ======= Memory map:======== ...... 00960000-00963000 r-xp 00000000 00:1b 7668734 ./lib2.so 00963000-00964000 rwxp 00003000 00:1b 7668734 ./lib2.so 00970000-00971000 r-xp 00970000 00:00 0 [vdso] 00e86000-00e89000 r-xp 00000000 00:1b 7668022 ./lib1.so 00e89000-00e8a000 rwxp 00003000 00:1b 7668022 ./lib1.so 08048000-08049000 r-xp 00000000 00:1b 7668748 ./test 08049000-0804a000 rw-p 00000000 00:1b 7668748 ./test 09cbf000-09ce0000 rw-p 09cbf000 00:00 0 [heap] ...... Abort(coredump) $ |
浠庣▼搴忕殑杈撳嚭鐩磋鐨勭湅鍒幫紝core 浜х敓鏄敱浜庡爢鍐呭瓨鍖哄煙錛?strong>09cbf000-09ce0000錛変腑璧峰鍦板潃涓?nbsp;0x09cbf028鐨勫唴瀛樺尯琚噴鏀句簡涓ゆ瀵艱嚧鐨勶紝璇ュ湴鍧姝e紡闈欐佹垚鍛樺彉閲?nbsp;vec_int鐨勭涓涓厓绱犵殑鍦板潃銆?/p>
涓轟粈涔堜細鍑虹幇鍚屼竴鍧楀唴瀛樺尯錛岃閲婃斁涓ゆ鐨勬儏褰㈠憿錛?/p>
鎴戜滑鐭ラ亾錛岄潤鎬佹垚鍛樺彉閲忎笌鍏ㄥ眬鍙橀噺綾諱技錛岄兘閲囩敤浜嗛潤鎬佸瓨鍌ㄦ柟寮忋傚浜庡姞浜嗛夐」 -fpic鎴?nbsp;-fPIC鐨勫叡浜簱錛岃繖浜涘彉閲忕殑鍦板潃閮藉瓨鏀懼湪璇ュ叡浜簱鐨勫叏灞鍋忕Щ琛紙Global Offset Table錛孏OT錛変腑銆?/p>
閫氳繃 objdump鎴栬?nbsp;readelf鍛戒護鍒嗘瀽鍏變韓搴?nbsp;lib1.so錛岀粨鏋滃涓嬶細
$ objdump -x -R lib1.so lib1.so: file format elf32-i386 ...... Sections: Idx Name Size VMA LMA File off Algn 0 .gnu.hash 000001e8 000000d4 000000d4 000000d4 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA ...... 18 .dynamic 000000d8 0000301c 0000301c 0000301c 2**2 CONTENTS, ALLOC, LOAD, DATA 19 .got 00000014 000030f4 000030f4 000030f4 2**2 CONTENTS, ALLOC, LOAD, DATA 20 .got.plt 00000114 00003108 00003108 00003108 2**2 CONTENTS, ALLOC, LOAD, DATA ...... DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE ...... 000030f4 R_386_GLOB_DAT __gmon_start__ 000030f8 R_386_GLOB_DAT _Jv_RegisterClasses 000030fc R_386_GLOB_DAT _ZN1A7vec_intE 00003104 R_386_GLOB_DAT __cxa_finalize ...... |
$ objdump -x -R lib1.so lib1.so: file format elf32-i386 ...... Sections: Idx Name Size VMA LMA File off Algn 0 .gnu.hash 000001e8 000000d4 000000d4 000000d4 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA ...... 18 .dynamic 000000d8 0000301c 0000301c 0000301c 2**2 CONTENTS, ALLOC, LOAD, DATA 19 .got 00000014 000030f4 000030f4 000030f4 2**2 CONTENTS, ALLOC, LOAD, DATA 20 .got.plt 00000114 00003108 00003108 00003108 2**2 CONTENTS, ALLOC, LOAD, DATA ...... DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE ...... 000030f4 R_386_GLOB_DAT __gmon_start__ 000030f8 R_386_GLOB_DAT _Jv_RegisterClasses 000030fc R_386_GLOB_DAT _ZN1A7vec_intE 00003104 R_386_GLOB_DAT __cxa_finalize ...... |
浠庝笂闈袱涓懡浠ょ殑杈撳嚭緇撴灉涓彲浠ョ湅鍑猴紝鍏變韓搴?nbsp;lib1.so涓?nbsp;GOT孌電殑璧峰鍐呭瓨鍦板潃涓?nbsp;000030f4錛屽ぇ灝忎負 20 瀛楄妭 (0x14)錛涢潤鎬佹垚鍛樺彉閲?nbsp;vec_int鍦ㄥ叡浜簱 lib1.so涓殑璧峰鍋忕Щ鍦板潃涓?nbsp;000030fc銆傛樉鐒訛紝vec_int浣嶄簬璇ュ叡浜簱鐨?nbsp;GOT孌靛唴銆?/p>
褰撳簲鐢ㄧ▼搴忓悓鏃墮摼鎺?nbsp;lib1.so鍜?nbsp;lib2.so鏃訛紝鍚屽悕闈欐佹垚鍛樺彉閲?nbsp;vec_int鍒嗗埆浣嶄簬鍏跺叡浜簱鐨?nbsp;GOT鍖恒傚綋紼嬪簭榪愯鏃訛紝緋葷粺浠庣鍙瘋〃涓煡鎵懼茍瑁呰澆鏋勯犱竴浠?nbsp;vec_int鏁版嵁錛岃繖鐐逛粠紼嬪簭榪愯鐨勮緭鍑虹粨鏋滐紙娓呭崟 4錛夌殑“Backtrace”閮ㄥ垎鍙互鐪嬪埌錛氬彧鏈?nbsp;lib1.so涓殑闈欐佹垚鍛樺彉閲忚瑁呰澆鏋勯狅紱鍚屾椂錛岄氳繃鍐呭瓨鏄犲皠錛?strong>Memory map錛夐儴鍒嗭紙娓呭崟 4錛夛紝鍙互瑙傚療鍒?nbsp;vec_int瀵硅薄鐨勫湴鍧 0xe89228姝eソ澶勫湪涓哄叡浜簱 lib1.so鍒嗛厤鐨勫彲璇誨唴瀛樺尯 00e89000-00e8a000涓細
00e89000-00e8a000 rwxp 00003000 00:1b 7668022 ./lib1.so |
鐒跺悗錛屽綋紼嬪簭緇撴潫鏃訛紝鍗村璇ュ彉閲忚繘琛屼簡涓ゆ鏋愭瀯鎿嶄綔錛岄氳繃 gdb鍒嗘瀽 core 鏂囦歡錛?/p>
娓呭崟 7. core 鏂囦歡鍒嗘瀽緇撴灉
$ gdb ./test core.28440 …… Core was generated by `./test'. Program terminated with signal 6, Aborted. #0 0x00970402 in __kernel_vsyscall () (gdb) (gdb) where #0 0x00970402 in __kernel_vsyscall () #1 0x00272d10 in raise () from /lib/libc.so.6 #2 0x00274621 in abort () from /lib/libc.so.6 #3 0x002aae5b in __libc_message () from /lib/libc.so.6 #4 0x002b2b16 in _int_free () from /lib/libc.so.6 #5 0x002b6030 in free () from /lib/libc.so.6 #6 0x005d1731 in operator delete () from /usr/lib/libstdc++.so.6 #7 0x00e88417 in __gnu_cxx::new_allocator<int>::deallocate (this=0xe89228, __p=0x9cbf028) at /usr/lib/gcc/i386-redhat-linux/.../ext/new_allocator.h:94 #8 0x00e88451 in std::_Vector_base<int, ... (this=0xe89228, __p=0x9cbf028, __n=4) at /usr/lib/gcc/.../include/c++/4.1.2/bits/stl_vector.h:133 #9 0x00e8849a in ~_Vector_base (this=0xe89228) at /usr/lib/gcc/.../include/c++/4.1.2/bits/stl_vector.h:119 #10 0x00e8850cin ~vector (this=0xe89228) at /usr/lib/gcc/.../stl_vector.h:272 #11 0x00961d6c in __tcf_0 () at lib2/lib.c:3 #12 0x00275c79 in __cxa_finalize () from /lib/libc.so.6 #13 0x00961c34 in __do_global_dtors_aux () from ./lib2.so #14 0x00962d3c in _fini () from ./lib2.so #15 0x0023a7de in _dl_fini () from /lib/ld-linux.so.2 #16 0x002759c9 in exit () from /lib/libc.so.6 #17 0x0025fdf4 in __libc_start_main () from /lib/libc.so.6 #18 0x080484c1 in _start () (gdb) |
浠庢竻鍗?7 涓彲浠ョ湅鍑猴紝浠庡撫 #14 寮濮嬶紝紼嬪簭榪涜 lib2.so涓殑鏋愭瀯鎿嶄綔錛岀洿鍒?#11錛岄兘榪愯鍦?nbsp;lib2.so涓紝褰撹繘鍏ュ撫 #10 鏃訛紝榪涜鍙橀噺鏋愭瀯鏃訛紝鍏跺湴鍧涓?nbsp;0x00e8850c錛岃鍦板潃涓殑瀵硅薄鏄▼搴忓惎鍔ㄦ椂鐢卞叡浜簱 lib1.so瑁呰澆鏋勯犲嚭鏉ョ殑錛堟竻鍗?1錛夛細
./lib1.so(_ZNSt6vectorIiSaIiEED1Ev+0x60)[0xe8850c] |
褰撶▼搴忕粨鏉熸椂錛岃繍琛屽簱 glibc媯嫻嬪埌鍏變韓搴?nbsp;lib2.so鏋愭瀯浜嗗茍闈炵敱鍏舵瀯閫犵殑瀵硅薄錛屽鑷翠簡 core dump銆?/p>
榪欑鎯呭喌涓嬶紝濡傛灉鏇挎崲浣跨敤閫夐」 -fpie鎴?nbsp;-fPIE錛屾搷浣滄楠や笌榪愯緇撴灉濡備笅鎵紺猴細
$ export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH $ g++ -g -o lib1.so -fPIE-rdynamic -shared lib1/lib.c $ g++ -g -o lib2.so -fPIE-rdynamic -shared lib2/lib.c $ g++ -g -pie -o test -L./ -l1 -l2 test.c $ ./test api1.h. vec_int[0] = 0, addr: 0x80e3028. vec_int[1] = 1, addr: 0x80e302c. vec_int[2] = 2, addr: 0x80e3030. vec_int[3] = 3, addr: 0x80e3034. vec_int addr: 0x75e224. $ |
紼嬪簭榪愯緇撴灉絎﹀悎鏈熸湜騫舵甯哥粨鏉熴?/p>
榪欐槸鍥犱負錛屽綋浣跨敤閫夐」 -fpie鎴?nbsp;-fPIE鏃訛紝鐢熸垚鐨勫叡浜簱涓嶄細涓洪潤鎬佹垚鍛樺彉閲忔垨鍏ㄥ眬鍙橀噺鍦?nbsp;GOT涓垱寤哄搴旂殑鏉$洰錛堥氳繃 objdump鎴?strong>readelf鍛戒護鍙互鏌ョ湅錛屾澶勪笉鍐嶈禈榪幫級錛屼粠鑰岄伩鍏嶄簡鐢變簬闈欐佸璞?#8220;鏋勯犱竴嬈★紝鏋愭瀯涓ゆ”鑰屽鍚屼竴鍐呭瓨鍖哄煙閲婃斁涓ゆ寮曡搗鐨勭▼搴?core dump銆?/p>
閫夐」 -fpie鍜?nbsp;-fPIE涓?nbsp;-fpic鍙?nbsp;-fPIC鐨勭敤娉曞緢鐩鎬技錛屽尯鍒湪浜庡墠鑰呮繪槸灝嗙敓鎴愮殑浣嶇疆鏃犲叧浠g爜鐪嬩綔鏄睘浜庣▼搴忔湰韜紝騫剁洿鎺ラ摼鎺ヨ繘璇ュ彲鎵ц紼嬪簭錛岃岄潪瀛樺叆鍏ㄥ眬鍋忕Щ琛?nbsp;GOT涓紱榪欐牱錛屽浜庡悓鍚嶇殑闈欐佹垨鍏ㄥ眬瀵硅薄鐨勮闂紝鍏舵瀯閫犱笌鏋愭瀯鎿嶄綔灝嗕繚鎸佷竴涓瀵瑰簲銆?/p>
閫氳繃浣跨敤閫夐」 -fpie鎴?nbsp;-fPIE浠f浛 -fpic鎴栬?nbsp;-fPIC錛屼嬌寰楃敓鎴愮殑鍏變韓搴撲笉浼氫負闈欐佹垚鍛樺彉閲忔垨鍏ㄥ眬鍙橀噺鍦?nbsp;GOT涓垱寤哄搴旂殑鏉$洰錛屽悓鏃朵篃灝遍伩鍏嶄簡閽堝鍚屽悕闈欐佸璞?#8220;鏋勯犱竴嬈★紝鏋愭瀯涓ゆ”鐨勪笉褰撴搷浣溿?br />
杞嚜錛?a >http://www.ibm.com/developerworks/cn/linux/l-cn-sdlstatic/
嫻嬭瘯鏄蔣浠跺紑鍙戣繃紼嬩腑鏋佸叾閲嶈鐨勪竴鐜紝璇﹀敖鍛ㄥ瘑鐨勬祴璇曡兘澶熷噺灝戣蔣浠禕UG錛屾彁楂樿蔣浠跺搧璐ㄣ傛祴璇曞寘鎷崟鍏冩祴璇曘佺郴緇熸祴璇曠瓑銆傚叾涓崟鍏冩祴璇曟槸鎸囬拡瀵硅蔣浠跺姛鑳藉崟鍏冩墍浣滅殑嫻嬭瘯錛岃繖閲岀殑鍔熻兘鍗曞厓鍙互鏄竴涓被鐨勫睘鎬ф垨鑰呮柟娉曪紝嫻嬭瘯鐨勭洰鐨勬槸鐪嬭繖浜涘熀鏈崟鍏冩槸鍚﹀伐浣滄甯搞傜敱浜庡崟鍏冩祴璇曠殑鍐呭寰堝熀紜錛屽洜姝ゅ彲浠ョ湅浣滄槸嫻嬭瘯宸ヤ綔鐨勭涓鐜紝璇ラ」宸ヤ綔涓鑸敱寮鍙戜漢鍛樿嚜琛屽畬鎴愩傚鏋滄潯浠跺厑璁革紝鍗曞厓嫻嬭瘯浠g爜鐨勫紑鍙戝簲涓庣▼搴忎唬鐮佺殑寮鍙戝悓姝ヨ繘琛屻?/p>
铏界劧涓嶅悓紼嬪簭鐨勫崟鍏冩祴璇曚唬鐮佷笉灝界浉鍚岋紝浣嗘祴璇曚唬鐮佺殑妗嗘灦鍗撮潪甯哥浉浼鹼紝浜庢槸渚垮嚭鐜頒簡涓浜涘崟鍏冩祴璇曠被搴擄紝CppUnit渚挎槸鍏朵腑涔嬩竴銆?/p>
CppUnit鏄疿Unit涓殑涓鍛橈紝XUnit鏄竴涓ぇ瀹舵棌錛岃繕鍖呮嫭JUnit鍜孭ythonUnit絳夈侰ppUnit綆鍗曞疄鐢紝瀛︿範鍜屼嬌鐢ㄨ搗鏉ラ兘寰堟柟渚匡紝緗戜笂宸叉湁涓浜涙枃绔犲鍏朵綔浠嬬粛錛屼絾鏈枃鏇寸潃閲嶄簬璁茶В鍏朵腑鐨勫熀鏈蹇靛拰浣跨敤鏂規硶錛屼互甯姪鍒濇鎺ヨЕCppUnit鐨勪漢鍛樺揩閫熷叆闂ㄣ?/p>
瀹夎
鐩墠錛孋ppUnit鐨勬渶鏂扮増鏈槸1.10.2錛屼綘鍙互浠庝笅闈㈠湴鍧鑾峰彇錛?/p>http://sourceforge.net/projects/cppunit
瑙e帇鍚庯紝浣犲彲浠ョ湅鍒癈ppUnit鍖呭惈濡備笅鐩綍錛?/p>
config錛?閰嶇疆鏂囦歡 contrib錛?contribution錛屽叾浠栦漢璐$尞鐨勫鍥翠唬鐮?doc錛?鏂囨。錛岄渶瑕侀氳繃doxygen宸ュ叿鐢熸垚錛屼篃鍙互鐩存帴浠巗ourceforge绔欑偣涓婁笅杞芥墦鍖呭ソ鐨勬枃妗?examples錛氱ず渚嬩唬鐮?include錛?澶存枃浠?lib錛?瀛樻斁緙栬瘧濂界殑搴?src錛?婧愭枃浠訛紝浠ュ強緙栬瘧搴撶殑宸ョ▼絳?/pre>鐒跺悗鎵撳紑src鐩綍涓嬬殑CppUnitLibraries宸ョ▼錛屾墽琛宐uild/batch build錛岀紪璇戞垚鍔熺殑璇濓紝鐢熸垚鐨勫簱鏂囦歡灝嗚鎷瘋礉鍒發ib鐩綍涓嬨?/p>
浣犱篃鍙互鏍規嵁闇瑕侀夋嫨鎵闇鐨勯」鐩繘琛岀紪璇戯紝鍏朵腑欏圭洰cppunit涓洪潤鎬佸簱錛宑ppunit_dll涓哄姩鎬佸簱錛岀敓鎴愮殑搴撴枃浠朵負錛?/p>
cppunit.lib錛?闈欐佸簱release鐗?cppunitd.lib錛?闈欐佸簱debug鐗?cppunit_dll.lib錛?鍔ㄦ佸簱release鐗?cppunitd_dll.lib錛氬姩鎬佸簱debug鐗?/pre>瑕佷嬌鐢–ppUnit錛岃繕寰楄緗ソ澶存枃浠跺拰搴撴枃浠惰礬寰勶紝浠C6涓轟緥錛岄夋嫨Tools/Options/Directories錛屽湪Include files鍜孡ibrary files涓垎鍒坊鍔?CppUnitPath%/include鍜?CppUnitPath%/lib錛屽叾涓?CppUnitPath%琛ㄧずCppUnit鎵鍦ㄨ礬寰勩?/p>
鍋氬ソ鍑嗗宸ヤ綔鍚庯紝鎴戜滑灝卞彲浠ョ紪鍐欒嚜宸辯殑鍗曞厓嫻嬭瘯浠g爜浜嗐傞渶璇存槑鐨勬槸錛孋ppUnit鎵鐢ㄧ殑鍔ㄦ佽繍琛屾湡搴撳潎涓哄綰跨▼鍔ㄦ佸簱錛屽洜姝や綘鐨勫崟鍏冩祴璇曠▼搴忎篃寰椾嬌鐢ㄧ浉搴旇緗紝鍚﹀垯浼氬彂鐢熷啿紿併?/p>
姒傚康
鍦ㄤ嬌鐢ㄤ箣鍓嶏紝鎴戜滑鏈夊繀瑕佽璇嗕竴涓婥ppUnit涓殑涓昏綾伙紝褰撶劧浣犱篃鍙互鍏堢湅鍚庨潰鐨勪緥瀛愶紝閬囧埌闂鍐嶅洖榪囧ご鏉ョ湅榪欎竴鑺傘?/p>
CppUnit鏍稿績鍐呭涓昏鍖呮嫭鍏釜鏂歸潰錛?/p>
1. 嫻嬭瘯瀵硅薄錛圱est錛孴estFixture錛?..錛夛細鐢ㄤ簬寮鍙戞祴璇曠敤渚嬶紝浠ュ強瀵規祴璇曠敤渚嬭繘琛岀粍緇囩鐞嗐?/p>
2. 嫻嬭瘯緇撴灉錛圱estResult錛夛細澶勭悊嫻嬭瘯鐢ㄤ緥鎵ц緇撴灉銆俆estResult涓庝笅闈㈢殑TestListener閲囩敤鐨勬槸瑙傚療鑰呮ā寮忥紙Observer Pattern錛夈?/p>
3. 嫻嬭瘯緇撴灉鐩戝惉鑰咃紙TestListener錛夛細TestListener浣滀負TestResult鐨勮瀵熻咃紝鎷呬換瀹為檯鐨勭粨鏋滃鐞嗚鑹層?/p>
4. 緇撴灉杈撳嚭錛圤utputter錛夛細灝嗙粨鏋滆繘琛岃緭鍑猴紝鍙互鍒跺畾涓嶅悓鐨勮緭鍑烘牸寮忋?/p>
5. 瀵硅薄宸ュ巶錛圱estFactory錛夛細鐢ㄤ簬鍒涘緩嫻嬭瘯瀵硅薄錛屽嫻嬭瘯鐢ㄤ緥榪涜鑷姩鍖栫鐞嗐?/p>
6. 嫻嬭瘯鎵ц浣擄紙TestRunner錛夛細鐢ㄤ簬榪愯涓涓祴璇曘?/p>
浠ヤ笂鍚勬ā鍧楃殑涓昏綾葷戶鎵跨粨鏋勫涓嬶細
Test TestFixture TestResult TestListener _______|_________ | | | | | TestSuccessListener TestComposite TestLeaf | | | |____________| TestResultCollector TestSuit | TestCase | TestCaller<Fixture> Outputter TestFactory TestRunner ____________________|_________________ | | | | TestFactoryRegistry CompilerOutputter TextOutputter XmlOutputter | TestSuiteFactory<TestCaseType>鎺ヤ笅鏉ュ啀瀵瑰叾涓竴浜涘叧閿被浣滀互浠嬬粛銆?/p>
Test錛氭墍鏈夋祴璇曞璞$殑鍩虹被銆?/p>
CppUnit閲囩敤鏍戝艦緇撴瀯鏉ョ粍緇囩鐞嗘祴璇曞璞★紙綾諱技浜庣洰褰曟爲錛夛紝鍥犳榪欓噷閲囩敤浜嗙粍鍚堣璁℃ā寮忥紙Composite Pattern錛夛紝Test鐨勪袱涓洿鎺ュ瓙綾籘estLeaf鍜孴estComposite鍒嗗埆琛ㄧず“嫻嬭瘯鏍?#8221;涓殑鍙惰妭鐐瑰拰闈炲彾鑺傜偣錛屽叾涓璗estComposite涓昏璧風粍緇囩鐞嗙殑浣滅敤錛屽氨鍍忕洰褰曟爲涓殑鏂囦歡澶癸紝鑰孴estLeaf鎵嶆槸鏈緇堝叿鏈夋墽琛岃兘鍔涚殑嫻嬭瘯瀵硅薄錛屽氨鍍忕洰褰曟爲涓殑鏂囦歡銆?/p>
Test鏈閲嶈鐨勪竴涓叕鍏辨帴鍙d負錛?/p>
virtual void run(TestResult *result) = 0;鍏朵綔鐢ㄤ負鎵ц嫻嬭瘯瀵硅薄錛屽皢緇撴灉鎻愪氦緇檙esult銆?/p>
鍦ㄥ疄闄呭簲鐢ㄤ腑錛屾垜浠竴鑸笉浼氱洿鎺ヤ嬌鐢═est銆乀estComposite浠ュ強TestLeaf錛岄櫎闈炴垜浠閲嶆柊瀹氬埗鏌愪簺鏈哄埗銆?/p>
TestFixture錛氱敤浜庣淮鎶や竴緇勬祴璇曠敤渚嬬殑涓婁笅鏂囩幆澧冦?/p>
鍦ㄥ疄闄呭簲鐢ㄤ腑錛屾垜浠粡甯鎬細寮鍙戜竴緇勬祴璇曠敤渚嬫潵瀵規煇涓被鐨勬帴鍙e姞浠ユ祴璇曪紝鑰岃繖浜涙祴璇曠敤渚嬪緢鍙兘鍏鋒湁鐩稿悓鐨勫垵濮嬪寲鍜屾竻鐞嗕唬鐮併備負姝わ紝CppUnit寮曞叆TestFixture鏉ュ疄鐜拌繖涓鏈哄埗銆?/p>
TestFixture鍏鋒湁浠ヤ笅涓や釜鎺ュ彛錛屽垎鍒敤浜庡鐞嗘祴璇曠幆澧冪殑鍒濆鍖栦笌娓呯悊宸ヤ綔錛?/p>
virtual void setUp();
virtual void tearDown();TestCase錛氭祴璇曠敤渚嬶紝浠庡悕瀛椾笂灝卞彲浠ョ湅鍑烘潵錛屽畠渚挎槸鍗曞厓嫻嬭瘯鐨勬墽琛屽璞°?/p>
TestCase浠嶵est鍜孴estFixture澶氱戶鎵胯屾潵錛岄氳繃鎶奣est::run鍒跺畾鎴愭ā鏉垮嚱鏁幫紙Template Method錛夎屽皢涓や釜鐖剁被鐨勬搷浣滆瀺鍚堝湪涓璧鳳紝run鍑芥暟鐨勪吉瀹氫箟濡備笅錛?/p>
// 浼唬鐮?nbsp;
void TestCase::run(TestResult* result)
{
result->startTest(this); // 閫氱煡result嫻嬭瘯寮濮?br /> if( result->protect(this, &TestCase::setUp) ) // 璋冪敤setUp錛屽垵濮嬪寲鐜
result->protect(this, &TestCase::runTest); // 鎵цrunTest錛屽嵆鐪熸鐨勬祴璇曚唬鐮?br /> result->protect(this, &TestCase::tearDown); // 璋冪敤tearDown錛屾竻鐞嗙幆澧?br /> result->endTest(this); // 閫氱煡result嫻嬭瘯緇撴潫
}榪欓噷瑕佹彁鍒扮殑鏄嚱鏁皉unTest錛屽畠鏄疶estCase瀹氫箟鐨勪竴涓帴鍙o紝鍘熷瀷濡備笅錛?/p>
virtual void runTest();鐢ㄦ埛闇浠嶵estCase媧劇敓鍑哄瓙綾誨茍瀹炵幇runTest浠ュ紑鍙戣嚜宸辨墍闇鐨勬祴璇曠敤渚嬨?/p>
鍙﹀榪樿鎻愬埌鐨勫氨鏄疶estResult鐨刾rotect鏂規硶錛屽叾浣滅敤鏄鎵ц鍑芥暟錛堝疄闄呬笂鏄嚱鏁板璞★級鐨勯敊璇俊鎭紙鍖呮嫭鏂█鍜屽紓甯哥瓑錛夎繘琛屾崟鑾鳳紝浠庤屽疄鐜板嫻嬭瘯緇撴灉鐨勭粺璁°?/p>
TestSuit錛氭祴璇曞寘錛屾寜鐓ф爲褰㈢粨鏋勭鐞嗘祴璇曠敤渚?/p>
TestSuit鏄疶estComposite鐨勪竴涓疄鐜幫紝瀹冮噰鐢╲ector鏉ョ鐞嗗瓙嫻嬭瘯瀵硅薄錛圱est錛夛紝浠庤屽艦鎴愰掑綊鐨勬爲褰㈢粨鏋勩?/p>
TestCaller錛歍estCase閫傞厤鍣紙Adapter錛夛紝瀹冨皢鎴愬憳鍑芥暟杞崲鎴愭祴璇曠敤渚?/p>
铏界劧鎴戜滑鍙互浠嶵estCase媧劇敓鑷繁鐨勬祴璇曠被錛屼絾浠嶵estCase綾葷殑瀹氫箟鍙互鐪嬪嚭錛屽畠鍙兘鏀寔涓涓祴璇曠敤渚嬶紝榪欏浜庢祴璇曚唬鐮佺殑緇勭粐鍜岀淮鎶ゅ緢涓嶆柟渚匡紝灝ゅ叾鏄偅浜涙湁鍏卞悓涓婁笅鏂囩幆澧冪殑涓緇勬祴璇曘備負姝わ紝CppUnit鎻愪緵浜員estCaller浠ヨВ鍐寵繖涓棶棰樸?/p>
TestCaller鏄竴涓ā鏉跨被錛屽畠浠ュ疄鐜頒簡TestFixture鎺ュ彛鐨勭被涓烘ā鏉垮弬鏁幫紝灝嗙洰鏍囩被涓煇涓鍚坮unTest鍘熷瀷鐨勬祴璇曟柟娉曢傞厤鎴怲estCase鐨勫瓙綾匯?/p>
鍦ㄥ疄闄呭簲鐢ㄤ腑錛屾垜浠ぇ澶氶噰鐢═estFixture鍜孴estCaller鐩哥粍鍚堢殑鏂瑰紡錛屽叿浣撲緥瀛愬弬瑙佸悗鏂囥?/p>
TestResult鍜孴estListener錛氬鐞嗘祴璇曚俊鎭拰緇撴灉
鍓嶉潰宸茬粡鎻愬埌錛孴estResult鍜孴estListener閲囩敤浜嗚瀵熻呮ā寮忥紝TestResult緇存姢涓涓敞鍐岃〃錛岀敤浜庣鐞嗗悜鍏剁櫥璁拌繃鐨凾estListener錛屽綋TestResult鏀跺埌嫻嬭瘯瀵硅薄錛圱est錛夌殑嫻嬭瘯淇℃伅鏃訛紝鍐嶄竴涓鍒嗗彂緇欏畠鎵綆¤緰鐨凾estListener銆傝繖涓璁捐鏈夊姪浜庡疄鐜板鍚屼竴嫻嬭瘯鐨勫縐嶅鐞嗘柟寮忋?/p>
TestFactory錛氭祴璇曞伐鍘?/p>
榪欐槸涓涓緟鍔╃被錛岄氳繃鍊熷姪涓緋誨垪瀹忓畾涔夎嫻嬭瘯鐢ㄤ緥鐨勭粍緇囩鐞嗗彉寰楄嚜鍔ㄥ寲銆傚弬瑙佸悗闈㈢殑渚嬪瓙銆?/p>
TestRunner錛氱敤浜庢墽琛屾祴璇曠敤渚?/p>
TestRunner灝嗗緟鎵ц鐨勬祴璇曞璞$鐞嗚搗鏉ワ紝鐒跺悗渚涚敤鎴瘋皟鐢ㄣ傚叾鎺ュ彛涓猴細
virtual void addTest( Test *test ); virtual void run( TestResult &controller, const std::string &testPath = "" );榪欎篃鏄竴涓緟鍔╃被錛岄渶娉ㄦ剰鐨勬槸錛岄氳繃addTest娣誨姞鍒癟estRunner涓殑嫻嬭瘯瀵硅薄蹇呴』鏄氳繃new鍔ㄦ佸垱寤虹殑錛岀敤鎴蜂笉鑳藉垹闄よ繖涓璞★紝鍥犱負TestRunner灝嗚嚜琛岀鐞嗘祴璇曞璞$殑鐢熷懡鏈熴?/p>
浣跨敤
鍏堣鎴戜滑鐪嬬湅涓涓畝鍗曠殑渚嬪瓙錛?/p>
#include <cppunit/TestCase.h>緙栬瘧鍚庤繍琛岋紝杈撳嚭緇撴灉涓猴細
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TextOutputter.h>
// 瀹氫箟嫻嬭瘯鐢ㄤ緥
class SimpleTest : public CppUnit::TestCase
{
public:
void runTest() // 閲嶈澆嫻嬭瘯鏂規硶
{
int i = 1;
CPPUNIT_ASSERT_EQUAL(0, i);
}
};
int main(int argc, char* argv[])
{
CppUnit::TestResult r;
CppUnit::TestResultCollector rc;
r.addListener(&rc); // 鍑嗗濂界粨鏋滄敹闆嗗櫒
SimpleTest t;
t.run(&r); // 榪愯嫻嬭瘯鐢ㄤ緥
CppUnit::TextOutputter o(&rc, std::cout);
o.write(); // 灝嗙粨鏋滆緭鍑?br />
return 0;
}!!!FAILURES!!!
Test Results:
Run: 1 Failures: 1 Errors: 0
1) test: (F) line: 18 E:/CppUnitExamples/SimpleTest.cpp
equality assertion failed
- Expected: 1
- Actual : 0涓婇潰鐨勪緥瀛愬緢綆鍗曪紝闇璇存槑鐨勬槸CPPUNIT_ASSERT_EQUAL瀹忋侰ppUnit瀹氫箟浜嗕竴緇勫畯鐢ㄤ簬媯嫻嬮敊璇紝CPPUNIT_ASSERT_EQUAL鏄叾涓箣涓錛屽綋鏂█澶辮觸鏃訛紝CppUnit渚夸細灝嗛敊璇俊鎭姤鍛婄粰TestResult銆傝繖浜涘畯瀹氫箟鐨勮鏄庡涓嬶細
CPPUNIT_ASSERT(condition)錛氬垽鏂璫ondition鐨勫兼槸鍚︿負鐪燂紝濡傛灉涓哄亣鍒欑敓鎴愰敊璇俊鎭?/p>
CPPUNIT_ASSERT_MESSAGE(message, condition)錛氫笌CPPUNIT_ASSERT綾諱技錛屼絾緇撴灉涓哄亣鏃舵姤鍛妋esssage淇℃伅銆?/p>
CPPUNIT_FAIL(message)錛氱洿鎺ユ姤鍛妋esssage閿欒淇℃伅銆?/p>
CPPUNIT_ASSERT_EQUAL(expected, actual)錛氬垽鏂璭xpected鍜宎ctual鐨勫兼槸鍚︾浉絳夛紝濡傛灉涓嶇瓑杈撳嚭閿欒淇℃伅銆?/p>
CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual)錛氫笌CPPUNIT_ASSERT_EQUAL綾諱技錛屼絾鏂█澶辮觸鏃惰緭鍑簃essage淇℃伅銆?/p>
CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta)錛氬垽鏂璭xpected涓巃ctual鐨勫亸宸槸鍚﹀皬浜巇elta錛岀敤浜庢誕鐐規暟姣旇緝銆?/p>
CPPUNIT_ASSERT_THROW(expression, ExceptionType)錛氬垽鏂墽琛岃〃杈懼紡expression鍚庢槸鍚︽姏鍑篍xceptionType寮傚父銆?/p>
CPPUNIT_ASSERT_NO_THROW(expression)錛氭柇璦鎵ц琛ㄨ揪寮廵xpression鍚庢棤寮傚父鎶涘嚭銆?/p>
鎺ヤ笅鏉ュ啀鐪嬬湅TestFixture鍜孴estCaller鐨勭粍鍚堜嬌鐢細
#include <cppunit/TestCase.h>緙栬瘧鍚庤繍琛岀粨鏋滀負錛?/span>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TextOutputter.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestRunner.h>
// 瀹氫箟嫻嬭瘯綾?br />class StringTest : public CppUnit::TestFixture
{
public:
void setUp() // 鍒濆鍖?br /> {
m_str1 = "Hello, world";
m_str2 = "Hi, cppunit";
}
void tearDown() // 娓呯悊
{
}
void testSwap() // 嫻嬭瘯鏂規硶1
{
std::string str1 = m_str1;
std::string str2 = m_str2;
m_str1.swap(m_str2);
CPPUNIT_ASSERT(m_str1 == str2);
CPPUNIT_ASSERT(m_str2 == str1);
}
void testFind() // 嫻嬭瘯鏂規硶2
{
int pos1 = m_str1.find(',');
int pos2 = m_str2.rfind(',');
CPPUNIT_ASSERT_EQUAL(5, pos1);
CPPUNIT_ASSERT_EQUAL(2, pos2);
}
protected:
std::string m_str1;
std::string m_str2;
};
int main(int argc, char* argv[])
{
CppUnit::TestResult r;
CppUnit::TestResultCollector rc;
r.addListener(&rc); // 鍑嗗濂界粨鏋滄敹闆嗗櫒
CppUnit::TestRunner runner; // 瀹氫箟鎵ц瀹炰綋
runner.addTest(new CppUnit::TestCaller<StringTest>("testSwap", &StringTest::testSwap)); // 鏋勫緩嫻嬭瘯鐢ㄤ緥1
runner.addTest(new CppUnit::TestCaller<StringTest>("testFind", &StringTest::testFind)); // 鏋勫緩嫻嬭瘯鐢ㄤ緥2
runner.run(r); // 榪愯嫻嬭瘯
CppUnit::TextOutputter o(&rc, std::cout);
o.write(); // 灝嗙粨鏋滆緭鍑?br />
return rc.wasSuccessful() ? 0 : -1;
}OK (2 tests)涓婇潰鐨勪唬鐮佷粠鍔熻兘涓婅娌℃湁浠涔堥棶棰橈紝浣嗙紪鍐欒搗鏉ュお綣佺悙浜嗭紝涓烘錛屾垜浠彲浠ュ熷姪CppUnit瀹氫箟鐨勪竴濂楄緟鍔╁畯錛屽皢嫻嬭瘯鐢ㄤ緥鐨勫畾涔夊拰娉ㄥ唽鍙樺緱鑷姩鍖栥備笂闈㈢殑浠g爜鏀歸犲悗濡備笅錛?/p>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TextOutputter.h>
#include <cppunit/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
// 瀹氫箟嫻嬭瘯綾?br />class StringTest : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(StringTest); // 瀹氫箟嫻嬭瘯鍖?br /> CPPUNIT_TEST(testSwap); // 娣誨姞嫻嬭瘯鐢ㄤ緥1
CPPUNIT_TEST(testFind); // 娣誨姞嫻嬭瘯鐢ㄤ緥2
CPPUNIT_TEST_SUITE_END(); // 緇撴潫嫻嬭瘯鍖呭畾涔?br />
public:
void setUp() // 鍒濆鍖?br /> {
m_str1 = "Hello, world";
m_str2 = "Hi, cppunit";
}
void tearDown() // 娓呯悊
{
}
void testSwap() // 嫻嬭瘯鏂規硶1
{
std::string str1 = m_str1;
std::string str2 = m_str2;
m_str1.swap(m_str2);
CPPUNIT_ASSERT(m_str1 == str2);
CPPUNIT_ASSERT(m_str2 == str1);
}
void testFind() // 嫻嬭瘯鏂規硶2
{
int pos1 = m_str1.find(',');
int pos2 = m_str2.rfind(',');
CPPUNIT_ASSERT_EQUAL(5, pos1);
CPPUNIT_ASSERT_EQUAL(2, pos2);
}
protected:
std::string m_str1;
std::string m_str2;
};
CPPUNIT_TEST_SUITE_REGISTRATION(StringTest); // 鑷姩娉ㄥ唽嫻嬭瘯鍖?br />
int main(int argc, char* argv[])
{
CppUnit::TestResult r;
CppUnit::TestResultCollector rc;
r.addListener(&rc); // 鍑嗗濂界粨鏋滄敹闆嗗櫒
CppUnit::TestRunner runner; // 瀹氫箟鎵ц瀹炰綋
runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
runner.run(r); // 榪愯嫻嬭瘯
CppUnit::TextOutputter o(&rc, std::cout);
o.write(); // 灝嗙粨鏋滆緭鍑?br />
return rc.wasSuccessful() ? 0 : -1;
}CppUnit鐨勭畝鍗曚粙緇嶅氨鍒版錛岀浉淇′綘宸茬粡浜嗚В浜嗗叾涓殑鍩烘湰姒傚康錛屼篃鑳藉寮鍙戝崟鍏冩祴璇曚唬鐮佷簡銆?br />
杞嚜錛?a >http://blog.csdn.net/freefalcon/article/details/753819
]]>