boost之测试
C/C++只提供了很有限的正確性驗(yàn)證/測試支持——assert宏(沒錯,它是一個宏,雖然它違背常識使用了小寫的形式),這是很不夠的。C++標(biāo)準(zhǔn)中的 std: : exception能夠處理運(yùn)行時異常、但并不能檢查代碼的邏輯,缺乏足夠的、語言級別的工具來保證軟件的正確性,使程序員很容易陷入與bug搏斗的泥沼中。
Boost 在這方面前進(jìn)了一大步: boost.assert庫增強(qiáng)了原始的運(yùn)行時assert 宏,static_assert庫提供了靜態(tài)斷言(編譯期診斷),而 lightweight_test(輕量)和 test庫則構(gòu)建了完整的單元測試框架。
assert
為使用boost.assert需要包含頭文件<boost/assert.hpp>,
即:#include <boost/assert.hpp>
基本用法
# define BOOST_ASSERT(expr)? ? ? ? ? ? ? ? ? ? ?assert (expr)
#define BOOST_ASSERT_MSG(expr, msg)? ? ?assert(expr)&&(msg))?
宏的參數(shù)expr表達(dá)式可以是任意(合法的)c++表達(dá)式,從簡單的關(guān)系比較到復(fù)雜的函數(shù)嵌套調(diào)用都允許。如果表達(dá)式值為true,那么斷言成立,程序會繼續(xù)向下執(zhí)行,否則斷言會引發(fā)一個異常,在終端上輸出調(diào)試信息并終止程序的執(zhí)行。
BOOST_ASSERT宏僅會在 debug模式下生效,在release模式下不會進(jìn)行編譯,不會影響到運(yùn)行效率,所以可以放心大膽地在代碼中使用BoosT_ASSERT 斷言。它不僅能夠診斷錯誤、保證程序正確運(yùn)行,而且其規(guī)范的大寫形式也能夠起到類似代碼注釋的作用,提醒代碼維護(hù)人員什么該做、什么不該做。
double func(int x) {BOOST_ASSERT_MSG(x!=0,"divided by zero");return 1.0/x; }禁用斷言
如果在頭文件<boost/assert.hpp>之前定義了宏 BOOST_DISABLE_ASSERTS,那么BOOST_ASSERT將會定義為((void)0),自動失效。但標(biāo)準(zhǔn)的assert宏并不會受影響,這可以讓程序員有選擇地關(guān)閉BOOST_ASSERT。
#include<cassert> #include<iostream> #include<boost/assert.hpp> #define BOOST_DISABLE_ASSERTSdouble func(int x) {BOOST_ASSERT(x!=0&&"divided by zero");std::cout<<"after boost_assert"<<std::endl;assert(x!=0&&"divided by zero");std::cout<<"after assert"<<std::endl;return 1.0/x; }int main() {func(0); } //Assertion `x!=0&&"divided by zero"' failed.擴(kuò)展用法
如果在頭文件<boost/assert.hpp>之前定義了宏BOOST_ENABLE_ASSERT_HANDLER,這將導(dǎo)致BOOST_ASSERT的行為發(fā)生改變:
 它將不再等同于assert宏,斷言的表達(dá)式無論是在 debug還是release模式下都將被求值。如果斷言失敗,會發(fā)生一個斷言失敗的函數(shù)調(diào)用boost::assertion_failed ()或者assertion_failed_msg()——這相當(dāng)于提供了一個錯誤處理handlere
?static_assert
static_assert庫把斷言的診斷時刻由運(yùn)行期提前到編譯期,讓編譯器檢查可能發(fā)生的錯誤,能夠更好地增加程序的健壯性,它模擬實(shí)現(xiàn)了C++標(biāo)準(zhǔn)里的static assert關(guān)鍵字。
用法
BOOST_STATIC_ASSERT使用了較復(fù)雜的技術(shù),但簡單來理解,它實(shí)際上最終是一個typedef,因此在編譯時同樣不會產(chǎn)生任何代碼和數(shù)據(jù),對運(yùn)行效率不會有任何影響——不論是 debug模式還是release模式。
BOOST_STATIC_ASSERT是一個編譯期斷言,使用了模板元編程技術(shù)實(shí)現(xiàn),雖然在很多方面它都與 BO0ST_ASSERT很相似,但用法還是有所不同的。最重要的區(qū)別是使用范圍:BOOST_ASSERT (expr)必須是一個能夠執(zhí)行的語句,它只能在函數(shù)域里出現(xiàn),而 BOOSTSTATIC_ASSERT則可以出現(xiàn)在程序的任何位置:名字空間域、類域或函數(shù)域。
template<typename T> T my_init(T a,T b) { BOOST_STATIC_ASSERT(sizeof(T)<sizeof(int)) return a<b? a:b; } int main() {std::cout<<my_init((short)1,(short)3); std::cout<<my_init(1L,3L);} // 如果使用支持C++11的編譯器(如ccc4.6以上、clang3.o 以上),那么我們可以使用BOOST_STATIC_ASSERT_MSG來輸出更明確的錯誤信息提示: BOOST_STATIc_ASSERT_MSG(sizeof(T)< sizeof(int), "only short or char");這樣提示信息會是: error: static assertion failed: only short or char使用建議:
static assert主要在泛型編程或模板元編程中用于驗(yàn)證編譯期常數(shù)或者模板類型參數(shù),可能讀者暫時不會用到它,但隨著對C++認(rèn)識的深入,將來就會發(fā)現(xiàn)它的好處。
使用static_assert時還需要注意,斷言的表達(dá)式必須能夠在編譯期求值,可能會讓很多人不太適應(yīng),這很正常,因?yàn)檫@正是邁向C++泛型編程和模板元編程的第一步。
test
test庫提供了一個用于單元測試的基于命令行界面的測試套件“Unit TestFramework”,簡稱UTF,還附帶有檢測內(nèi)存泄漏的功能,比其他的單元測試庫更強(qiáng)大更方便好用。它不僅能夠支持簡單的測試,也能夠支持全面的單元測試,并且還具有程序運(yùn)行監(jiān)控功能,是一個用于保證程序正確性的強(qiáng)大工具。
test庫包含兩個庫文件,需要編譯才能使用,在jamfile里指定lib的語句如下:
lib boost_unit_test_framework ;//單元測試框架庫
lib boost test exec monitor;\\//程序執(zhí)行監(jiān)視庫
#include<boost/test/unit_test.hpp>
最小化測試
#include<boost/test/minimal.hpp>
入口函數(shù):
minimal test內(nèi)部已經(jīng)實(shí)現(xiàn)了main ( ),因此我們不必再編寫自己的main(),只需再要實(shí)現(xiàn)一個test_main ()函數(shù),它是minimal test的真正功能函數(shù)。
test_main ()函數(shù)的聲明與標(biāo)準(zhǔn)的main ()很相似:
int test main ( int argc, char* argv [])
測試斷言
提供四個測試斷言宏
| BOOST_CHECK(e) | 斷言測試通過 不通過不影響程序執(zhí)行 | 
| BOOST_REQUIRE(e) | 要求測試必須通過 否則程序停止執(zhí)行 | 
| BOOST_ERROR(S) | 給出一個錯誤信息 程序繼續(xù)執(zhí)行 | 
| BOOST_FAIL(s) | 給出一個錯誤 程序運(yùn)行終止進(jìn)行 | 
實(shí)例測試format
#include<boost/format.hpp> #include<boost/test/minimal.hpp> #include<iostream> int test_main(int argc,char* argv[]) {using namespace boost;format fmt("%d-%d");BOOST_CHECK(fmt.size()!=0);fmt %12 %34;BOOST_REQUIRE(fmt.str()=="12-34");BOOST_ERROR("演示一條錯誤信息");fmt.clear(); fmt%12; try {std::cout<<fmt; } catch(...) {BOOST_FAIL("致命錯誤,測試終止"); } return 0;} // 演示一條錯誤信息 in function: 'int test_main(int, char**)' 致命錯誤,測試終止 in function: 'int test_main(int, char**)'單元測試框架
test庫提供了強(qiáng)大的單元測試框架(UTF),它為軟件開發(fā)的基本領(lǐng)域——單元測試提供了簡單而富有彈性的解決方案,可以滿足開發(fā)人員從高到低的各種需求,它的優(yōu)點(diǎn)包括:
易于理解,任何人都可以很容易地構(gòu)建單元測試模塊;
提供測試用例、測試套件的概念,并能夠以任意的復(fù)雜度組織它們;提供豐富的測試斷言,能夠處理各種情況,包括C++異常;
可以很容易地初始化測試用例、測試套件或者整個測試程序;可以顯示測試進(jìn)度,對于大型測試非常有用;
測試信息可以顯示為多種格式,如普通文本或者XML格式;支持命令行,可以指定運(yùn)行任意一個測試套件或測試用例;
支持命令行,可以指定運(yùn)行任意一個測試套件或測試用例;
還有許多更高級的用法。
測試斷言
test 庫同樣提供minimal test 里的四個基本的測試斷言: BOOST_CHECK、BOOSTREQUIRE、BOOST_ERROR和 BOOST_FAIL(但實(shí)現(xiàn)是不同的)。它們是最基本的測試斷言,能夠在任何地方使用,但同時為了通用性也不具有其他斷言的好處,我們應(yīng)當(dāng)盡量少使用。
測試斷言的形式是 BOOST_LVL_XXX,例如BOOST_CHECK_EQUAL、BOOST_WARN_GT,詳細(xì)命名規(guī)則如下:
BOOST??BOOST
 遵循Boost庫的命名規(guī)則,宏一律以大寫的 BOOST開頭;
 LVL
 斷言的級別。WARN是警告級,不影響程序運(yùn)行,也不增加錯誤數(shù)量;CHECK是檢查級別,如果斷言失敗增加錯誤數(shù)量,但不影響程序運(yùn)行:REQUIRE是最高的級別,如果斷言失敗將增加錯誤數(shù)量并終止程序運(yùn)行。最常用的斷言級別是CHECK,WARN可以用于不涉及程序關(guān)鍵功能的測試,只有當(dāng)斷言失敗會導(dǎo)致無法繼續(xù)進(jìn)行測試時才能夠使用REQUIRE;
 XXX
 各種具體的測試斷言,如斷言相等/不等、拋出/不拋出異常、大于或小于等。
常用的斷言:
| BOOST_LVL_EQUAL(1,r) | 檢測l==r,當(dāng)測試失敗時會給出詳細(xì)的信息。它不能用于浮點(diǎn)數(shù)的比較,浮點(diǎn)數(shù)的相等比較應(yīng)使用 BOOST_LVL_CLOSE; | 
| BOOST_LVL_GE(1,r) | :檢測l>=r,同樣的還有GT (l>r)、LT ( l<r)、LE(l<=r)和 NE( l!=r),它們用于測試各種不等性; | 
| BOOST_LVL_THROW(e,ex) | 檢測表達(dá)式e拋出指定的ex異常; | 
| BOOST_LVL_NO_THROW(e) | 檢測表達(dá)式e不拋出任何異常; | 
| BOOST_LVL_MESSAGE(e,msg) | 它與不帶 MESSAGE后綴的斷言功能相同,但測試失敗時給出指定的消息; | 
| BOOST_TEST_NESSAGE(msg) | 它僅輸出通知用的信息,不含有任何警告或者錯誤,默認(rèn)情況不會顯示。 | 
測試主體
test庫將測試程序定義為一個測試模塊,由測試安裝、測試主體、測試清理和測試運(yùn)行器四個部分組成。測試主體是測試模塊的實(shí)際運(yùn)行部分,由測試用例和測試套件組織成測試樹的形式。
測試用例:
測試用例是一個包含多個測試斷言的函數(shù),它是可以被獨(dú)立執(zhí)行測試的最小單元,各個測試用例之間是無關(guān)的,發(fā)生的錯誤不會影響到其他測試用例。
要添加測試用例需要向UTF注冊。在 test庫中,可以采用手工或者自動兩種形式,通常自動的方式更加簡單易用,可以簡化測試代碼的編寫。我們使用宏 BOOST_AoTO_TEST_CASE像聲明函數(shù)一樣創(chuàng)建測試用例,它的定義是:
#define BOOST_AUTO_TEST_CASE(test_name) BOOST_AUTO_TEST_CASE(t_casel) {BOOST_CHECK_EQUAL(1,1)'.... }測試套件
測試套件是測試用例的容器,它包含一個或多個測試用例,可以將繁多的測試用例分組管理,共享安裝/清理代碼,更好地組織測試用例。
測試套件同樣可以有手工和自動兩種使用方式,
自動方式使用兩個宏 BOOST_AUTO_TEST_SUITE和BOOST_AUTO_TEST_SUITE_END,它們的定義是:
#define? BOOST_AUTO_TEST_SUITE(suite_name)
#define? BOOST_AUTO_TEST_SUITE_END;
這兩個宏必須成對使用,宏之間的所有測試用例都屬于這個測試套件。一個c++源文件中可以有任意多個測試套件,測試套件也可以任意嵌套,沒有深度的限制。測試套件的名字一律以s開頭,例如:
BOOST_AUto_TEST_SUITE((s_suite)BOOST_AUTO_TEST_CASE(t_case1) { BOOST_CHECK_EQUAL(1,1); .... } BOOST_AUTO_CASE(t_CASE2) { BOOST_CHECK_EQUAL(1,1); ... } BOOST_AUto_TEST_SUITE_END();主測試套件
任何UTF單元測試程序都必須存在唯一一個主測試套件,它是整個測試樹的根節(jié)點(diǎn),其他的測試套件都是它的子節(jié)點(diǎn)。
 主測試套件的定義可以使用宏BOOST_TEST_MAIN或者BOOST_TEST_MODULE,它們必須出現(xiàn)在<boost/test/unit_test.hpp>之前。
 定義了主測試套件的源文件里可以不使用宏 BOOST_AUTO_TEST_SUITE 和 BOOST.AUTO_TEST_SUITE_END來組織測試用例,因?yàn)榇藭r所有測試用例都自動屬于主測試套件(當(dāng)然用了也不算錯)。
測試實(shí)例
#define BOOST_TEST_MAIN//定義主測試套件#include<boost/test/included/unit_test.hpp> #include<boost/smart_ptr.hpp>using namespace boost;BOOST_AUTO_TEST_SUITE(s_smart_prt);BOOST_AUTO_TEST_CASE(t_soped_ptr) {scoped_ptr<int>p(new int(857));BOOST_CHECK(p);BOOST_CHECK_EQUAL(*p,874);p.reset();BOOST_CHECK(p==0); } BOOST_AUTO_TEST_CASE(t_share_ptr) {shared_ptr<int>p1(new int(100));BOOST_CHECK(p1);BOOST_CHECK_EQUAL(*p1,100);BOOST_CHECK_EQUAL(p1.use_count(),1);shared_ptr<int>p2=p1;BOOST_CHECK(p2);BOOST_CHECK_EQUAL(p2.use_count(),2);*p1=255;BOOST_CHECK_EQUAL(*p1,225);BOOST_CHECK_GT(*p1,200); } BOOST_AUTO_TEST_SUITE_END() //Running 2 test cases... /root/boost/02/smart_ptr.cpp(17): error: in "s_smart_prt/t_soped_ptr": check *p == 874 has failed [857 != 874] /root/boost/02/smart_ptr.cpp(34): error: in "s_smart_prt/t_share_ptr": check *p1 == 225 has failed [255 != 225]*** 2 failures are detected in the test module "Master Test Suite"測試夾具
測試安裝執(zhí)行測試前的準(zhǔn)備工作,初始化測試用例或測試套件所需的數(shù)據(jù)。測試清理是測試安裝的反向操作,執(zhí)行必要的清理工作。
測試安裝和測試清理的動作很像C++中的構(gòu)造函數(shù)和析構(gòu)函數(shù),故可以定義一個輔助類,它的構(gòu)造函數(shù)和析構(gòu)函數(shù)分別執(zhí)行測試安裝和測試清理,之后我們就可以在每個測試用例最開始聲明一個對象,它將自動完成測試安裝和測試清理。
基于這個基本原理,UTF中定義了“測試夾具”的概念,它實(shí)現(xiàn)了自動的測試安裝和測試清理,就像是一個夾在測試用例或測試套件兩端的“夾子”。測試夾具不僅可以用于測試用例,也可以用于測試套件和單元測試全局。
使用夾具 必須是一個類
struct test_fixture_name { test_fixture_name(){} ~test_fixture_name(){} }指定測試用例和測試套件的夾具類需要使用另外兩個宏:
#define BOOST_FIXTURE_TEST_SUITE( suite_name,fixture_name )
#define BOOST_FIXTURE_TEST_CASE ( test_name,fixture_name)
全局測試夾具需要使用另一個宏 BOOST_GLOBAL_FIXTURE,它定義的夾具類被應(yīng)用于整個測試模塊的所有測試套件——包括主測試套件。
#define BOOST_TEST_MAIN #include<boost/test/included/unit_test.hpp>#include<boost/assign.hpp> #include<vector> #include<iostream> using namespace boost; // 全局 struct global_fixture{global_fixture(){std::cout<<("globakl setup\n");}~global_fixture(){std::cout<<("global teardown\n");} }; // 定義全局夾具類 BOOST_GLOBAL_FIXTURE(global_fixture);// 測試套件struct assign_fixture {assign_fixture(){std::cout<<("suit setip\n");}~assign_fixture(){std::cout<<("suit: teardown");}std::vector<int>v; }; BOOST_FIXTURE_TEST_SUITE(s_assign,assign_fixture);BOOST_AUTO_TEST_CASE(t_assign) {using namespace boost::assign;v+=1,2,3,4;BOOST_CHECK_EQUAL(v.size(),4);BOOST_CHECK_EQUAL(v[2],3);} BOOST_AUTO_TEST_CASE(t_assign2) {using namespace boost::assign;push_back(v)(10)(20)(30);BOOST_CHECK_EQUAL(v.size(),3);BOOST_CHECK_GE(v[0],v[1]); } //globakl setup Running 2 test cases... suit setip suit: teardownsuit setip /root/boost/02/assgin_test.cpp(43): error: in "s_assign/t_assign2": check v[0] >= v[1] has failed [10 < 20] suit: teardown *** 1 failure is detected in the test module "Master Test Suite" global teardownBOOST_AUTO_TEST_SUITE_END()
 ?
總結(jié)
 
                            
                        - 上一篇: 用argis和envi出对比图,带roi
- 下一篇: SpringBoot Shiro 配置自
