boost 正確性與測試

來源:互聯網
上載者:User

 boost.assert庫增強了原始的運行時assert宏,static_assert庫提供了靜態斷言(編譯期診斷),而boost.test庫則構建了完整的單元測試架構.

assert:
 boost.assert提供的主意工具是BOOST_ASSERT宏,它類似c標準中的assert宏,提供運行時的斷言。
#include <boost/assert.hpp>
基本用法:
 預設情況BOOST_ASSERT宏等同於assert宏,斷言運算式為真,即
#define BOOST_ASSERT(expr) assert(expr)
樣本:
#include <boost/assign.hpp>
using namespace boost;
using namespace std;

double func(int x)
{
 //宏還使用操作符&&向運算式增加了斷言資訊,當宣告失敗時,可以給出具體描述性文字
 BOOST_ASSERT(x != 0 && "divided by zero");
 return 1.0 / x;
}
int main()
{
 func(0);
 system("pause");
 return 0;
}

禁止斷言:
 如果在標頭檔<boost/assert.hpp>之前定義了宏BOOST_DISABLE_ASSERTS,那麼BOOST_ASSERT
將會定義為((void)0),自動失效,但標準的assert宏並不會受影響。
樣本:
#include <iostream>
#define BOOST_DISABLE_ASSERTS
#include <boost/assign.hpp>
#include <cassert>
using namespace boost;
using namespace std;
double func(int x)
{
 BOOST_ASSERT(x != 0 && "divided by zero");
 cout<<"after BOOST_ASSERT"<<endl;
 assert(x != 0 && "divided by zero");
 cout<<"after"<<endl;
 return 1.0 / x;
}
int main()
{
 func(0);
 system("pause");
 return 0;
}

擴充用法:
 如果在標頭檔<boost/assert.hpp>之前定義了宏BOOST_ENABLE_ASSERT_HANDLER,這將導致BOOST_ASSERT的行為發生改變.
 它將不再等同於assert宏,斷言的運算式無論是在debug還是release模式下都將被求值,如果宣告失敗,會發生一個宣告失敗的函數調用boost::assertion_failed()--這相當於提供了一個錯誤處理handle.
 函數assertion_failed()聲明在boost名字空間裡,但特意被設計為沒有具體實現,其聲明如下:
namespace boost
{
 void assertion_failed(char const * expr, char const* function, char const *file, long line);
}
 當宣告失敗時,BOOST_ASSERT宏會把斷言運算式字串,調用函數名(使用BOOST_CURRENT_FUNCTION),所在源檔案名稱和行號都傳遞給assertion_failed()函數處理,使用者需要自己實現assertion_failed()函數,以恰當的方式處理錯誤--通常是記錄日誌或拋出異常。
示範:
#include <iostream>
#define BOOST_ENABLE_ASSERT_HANDLER
#include <boost/format.hpp>
#include <boost/assert.hpp>
#include <cassert>
using namespace boost;
using namespace std;
namespace boost
{
 void assertion_failed(char const * expr, char const * function, char const * file, long line)
 {
  boost::format fmt("Assertion failed!\n Expression: %s\nFunction:%s\nFile: %s\nLine: %ld\n\n");
  fmt % expr % function%file%line;
  cout<<fmt;
 }
}
double func(int x)
{
 BOOST_ASSERT(x != 0 && "divided by zero");
 return 1.0 / x;
}
int main()
{
 func(0);
 system("pause");
 return 0;
}
 BOOST_ASSERT這種錯誤handle用法很有用,適合那些需要有統一錯誤處理方式的地方,最常見的就是函數入口參數檢查,在函數入口斷言參數,當參數出錯時拼錯誤字串,拋出參數異常類,同時終止函數的流程。
 如果擔心泄露原始碼資訊,可以選擇地輸出錯誤訊息,或對字串加密
 拋出異常的assertion_failed函數的實現可以這樣:
void assertion_failed(...)
{
 string str;
 ...
 throw std::invalid_argument(str);
}

BOOST_VERIFY:
 BOOST_VERIFY與BOOST_ASSERT僅有一點區別:斷言的運算式一定會被求值,在運用斷言運算(而不僅僅是錯誤檢查)及驗證函式傳回值時很有用.
示範:
#include <boost/assert.hpp>
...
int len;
BOOST_VERIFY(len=strlen("123"));//len被求值
 注意,在release模式下同樣失效,程式最好不應該依賴它的副作用.

static_assert:
 assert和BOOST_ASSERT是運行時斷言
 static_assert庫把斷言的診斷時刻由運行提前到編譯期。
#include <boost/static_assert.hpp>
用法:
 static_assert庫定義了宏BOOST_STATIC_ASSERT,用來進行編譯期斷言。
 BOOST_STATIC_ASSERT使用了較複雜的技術,但簡單來理解,它實際上最終是一個typedef,因此在編譯時間同樣不會產生任何代碼和資料,對運行效率不會有任何影響--不論是debug還是release模式。
 BOOST_STATIC_ASSERT和BOOST_ASSERT最重要的區別是使用範圍,BOOST_ASSERT(assert)必須是一個能夠執行的語句,它只能在函數域裡出現,而BOOST_STATIC_ASSERT則可以出現在程式任何位置:名字空間域,類域或函數域。

示範:簡單模板函數my_min,出於某種目的,它僅支援short或char類型
#include <iostream>
#include <boost/static_assert.hpp>
using namespace boost;
using namespace std;
template<typename T>
T my_min(T a, T b)
{
 BOOST_STATIC_ASSERT(sizeof(T) < sizeof(int));
 return a < b ? a : b;
}
int main()
{
 cout<<my_min((short)1, (short)3);
 cout<<my_min(1L, 3L);
 system("pause");
 return 0;
}
 斷言的錯誤資訊可能不夠明顯,但它能夠指明錯誤的位置,並為解決錯誤指出了基本方向。
 BOOST_STATIC_ASSERT在類域和名字空間域的使用方式與在函數域方式相同,例如:
namespace my_space
{
 class empty_class
 {
  BOOST_STATIC_ASSERT(sizeof(int) >= 4);
 };
 //名字空間域靜態斷言,是一個“空類”
 BOOST_STATIC_ASSERT(sizeof(empty_class) == 1);
}
 c++不允許大小為0的類會對象的存在,通常的“空類”會由編譯器在裡面安插一個類型為char的成員變數,令它有一個確定的大小。

使用建議:
 BOOST_STATIC_ASSERT主要在泛型程式設計或模板元編程中用於驗證編譯期常數或者模板型別參數。使用BOOST_STATIC_ASSERT時注意:斷言的運算式必須能夠在編譯期求值。

test:
 test庫提供了一個用於單元測試的基於命令列介面的測試套件Unit Test Framework,簡稱UTF,還附帶有檢測記憶體泄露的功能,比其他的單元測試庫更強大,它不僅支援簡單測試,還能支援全面的單元測試,並且還具有程式運行監控功能,是一個用於保證程式正確性的強大工具
#include <boost/test/unit_test.hpp>

編譯test庫:
 test庫編譯,bjam命令如下:
 bjam -toolset= msvc -with-test -build-type=complete stdlib=stlport stage
 test庫提供了先行編譯源碼檔案,標頭檔<boost/test/included/unit_test.hpp>包含了test庫所有實現代碼,因此需要在工程加入cpp檔案:
#define BOOST_TEST_MAIN //定義主測試套件,是測試main函數入口
#include <boost/test/included/unit_test.hpp>
這樣,把test的所有實現代碼編譯進行測試程式,其他測試套件的原始碼檔案仍然需要包含<boost/test/unit_test.hpp>, 但前面應加入宏定義BOOST_TEST_INCLUDED,告訴test庫使用源碼的使用方式即:
#define BOOST_TEST_INCLUDEED
#include <boost/test/unit_test.hpp>
相當於在test_main.cpp中編譯了test的靜態庫,而其他檔案則僅包含test庫的聲明,直接使用編譯好的靜態庫。

最小化的測試套件:
 test庫提供了一個最小化的測試套件,minimal test,不需要對test庫做任何形式的編譯,只需要包含標頭檔<boost/test/minimal.hpp>
#include <boost/test/minimal.hpp>
 它只提供最基本的單元測試功能,沒有UTF那麼強大,不支援多個測試案例,能夠使用的測試斷言很少,但簡單小巧,適合入門和簡單的測試。
 標頭檔<boost/test/minimal.hpp>中已經實現了一個main(),因此不必再定義自己的main(),只需要實現一個test_main()函數,它是minimal test的真正功能函數。
 test_main()函數的聲明與標準的main()很相似;
int test_main(int argc, char* argv[])
 在test_main()的函數體內,可以使用四個測試斷言宏,
 【1】BOOST_CHECK(predicate):斷言測試通過,如不通過不影響程式執行
 【2】BOOST_REQUIRE(predicate):要求測試必須通過,否則程式停止執行;
 【3】BOOST_ERROR(message):給出一個錯誤資訊,程式繼續執行;
 【4】BOOST_FAIL(message):給出一個錯誤資訊,程式終止。
示範:minimal test用法,簡單測試一下format庫:
#include <iostream>
#include <boost/test/minimal.hpp>
#include <boost/format.hpp>
int test_main(int argc, char* argv[]) //測試主函數
{
 using namespace boost;
 format fmt("%d-%d");
 BOOST_CHECK(fmt.size() != 0);//斷言format對象已經初始化
 fmt %12 % 34;
 BOOST_REQUIRE(fmt.str()=="12-34"); //驗證格式化結果
 system("pause");
 BOOST_ERROR("示範一條錯誤訊息"); //不影響程式的執行
 system("pause");
 fmt.clear();
 fmt %12;
 try
 {
  std::cout <<fmt;      //輸入參數不完整,拋出異常
 }
 catch (...)
 {
  BOOST_FAIL("致命錯誤, 測試終止");
 }
 system("pause");
 return 0;
}
 minimal test僅適用於單元測試的示範,或者規模較小的程式。
 
單元測試架構簡介:
 test庫提供了強有力的單元測試架構(UTF),它為軟體開發的基本領域--單元測試提供了簡單而富有彈性的解決方案.
 優點:
 【1】易於理解,任何人都可以很容易地構建單元測試模組
 【2】提供測試案例,測試套件的概念,並能夠以任意的複雜度組織它們。
 【3】提供豐富的測試斷言,能夠處理各種情況,包括c++異常.
 【4】可以很容易地初始化測試案例,測試套件或者整個測試程式; 
 【5】可以顯示測試進度,這對於大型測試是非常有用的。
 【6】測試資訊可以顯示為多種格式,如平檔案或者xml格式;
 【7】支援命令列,可以指定運行任意一個測試套件或測試案例;
 【8】還有許多更進階的用法。
下面詳細介紹UTF的各個組成部分,首先是測試斷言,它是單元測試的基本工具.

測試斷言:
 在test庫中,測試斷言是一組命名清楚的宏,它們用法類似BOOST_ASSERT,斷言測試通過,如果測試失敗,則會記錄出錯的檔案名稱和行號以及錯誤資訊。
 test庫的一個典型的測試斷言是BOOST_CHECH_EQUAL,形式是BOOST_XXX_YYY,具體命名規則如下:
 【1】BOOST_:遵循Boost庫的命名規則,宏以大寫的BOOST開頭。
 【2】XXX:斷言的層級,WARN是警告,不影響程式運行,也不增加錯誤數量,CHECK是檢查層級,如果宣告失敗增加錯誤數量,但不影響程式運行,REQUIRE是最高的層級,如果宣告失敗將增加錯誤數量並終止程式運行,最常用的斷言層級是CHECK,WARN可以用於不涉及程式關鍵功能的測試,只有當宣告失敗會導致無法繼續進行測試時才能夠使用REQUIRE;
 【3】YYY;各種具體測試斷言,如斷言相等/不等,拋出/不拋出異常,大於或小於等等.
BOOST_CHECK,BOOST_REQUIRE,BOOST_ERROR和BOOST_FAIL,是最基本的測試斷言,能夠在任何地方使用,但同時為了通用性也不具有其他斷言的好處,應當盡量少使用它們.
test庫中最常用的幾個測試斷言:
 【1】BOOST_XXX_EQUAL(l, r);檢查l == r,當測試失敗時會給出詳細資料,它不能用於浮點數的比較,浮點數的相等比較應使用BOOST_XXX_CLOSE;
 【2】BOOST_XXX_GE(l, r):檢查l>=r,同樣的還有GT(l<r),LT(l<r),LE(l<=r)和NE(l !=r),它們用於測試各種不等性.
 【3】BOOST_XXX_THROW(expr, exception):檢測運算式expr拋出指定的exception異常.
 【4】BOOST_XXX_NO_THROW(expr, exception):檢測運算式expr不拋出指定的exception異常.
 【5】BOOST_XXX_MESSAGE(expr,message):它與不帶MESSAGE尾碼的斷言功能相同, 但測試失敗時給出指定訊息;
 【6】BOOST_TEST_MESSAGE(message):它僅輸出通知用的資訊,不含有任何警告或者錯誤,預設情況下不會顯示.

測試案例與套件:
 test庫將測試程式定義為一個測試模組,有測試安裝,測試主體,測試清理和測試回合器四個部分組成,測試主體是測試模組的實際運行部分,由測試案例和測試套件組織成測試樹的形式.
 測試案例是一個包含多個測試斷言的函數,它是可以被獨立執行測試的最小單元,各個測試案例之間是無關的,發生的錯誤不會影響套其他測試案例;
 要添加測試案例,需要向UTF註冊,在test庫中,可以採用手工或者自動兩種形式,通常自動的方式更加簡單易用,可以簡單測試代碼的編寫,我們使用宏BOOST_AUTO_TEST_CASE像聲明函數一樣建立測試案例,它的定義:
#define BOOST_AUTO_TEST_CASE(test_name)
 宏參數test_name是測試案例的名字,一般以t開頭,表明整個名字是一個測試案例:
例如:
BOOST_AUTO_TEST_CASE(t_case1) //測試案例聲明
{
 BOOST_CHECH_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_suite1) //測試套件開始
BOOST_AUTO_TEST_CASE(t_case1) //測試案例聲明
{
 BOOST_CHECH_EQUAL(1, 1);
 ...
}
BOOST_AUTO_TEST_CASE(t_case2) //測試案例聲明
{
 BOOST_CHECH_EQUAL(1, 1);
 ...
}
BOOST_AUTO_TEST_SUITE_END() //測試套件結束
 任何一個UTF單元測試程式都必須存在一個主測試套件,它是整個測試樹的根節點,其他的測試套件都是它的子節點。
 主測試套件的定義可以使用宏BOOST_TEST_MAIN或者BOOST_TEST_MODULE,定義了這個宏的源檔案中不需要再有宏BOOST_AUTO_TEST_SUITE和BOOST_AUTO_TEST_SUITE_END,所有測試案例都自動屬於主測試套件.

測試執行個體:
///////////////////////////////////////////////
//主檔案
#include <iostream>
#define BOOST_TEST_MAIN
#include <boost/test/included/unit_test.hpp>
using namespace boost;
///////////////////////////////////////////////
//另一個cpp檔案
#define BOOST_TEST_INCLUDED
#include <boost/test/unit_test.hpp>
#include <boost/smart_ptr.hpp>
using namespace boost;
BOOST_AUTO_TEST_SUITE(s_smart_ptr)

BOOST_AUTO_TEST_CASE(t_scoped_ptr)
{
 scoped_ptr<int> p(new int(874));
 BOOST_CHECK(p);
 BOOST_CHECK_EQUAL(*p, 874);  //測試解引用的值
 p.reset();      //scoped_ptr複位
 BOOST_CHECK(p == 0);   //為空白指標
}

BOOST_AUTO_TEST_CASE(t_shared_ptr)
{
 shared_ptr<int> p(new int(874));
 BOOST_CHECK(p);
 BOOST_CHECK_EQUAL(*p, 874);     //測試解引用的值
 BOOST_CHECK_EQUAL(p.use_count(), 1);  //引用計數為1
 shared_ptr<int> p2 = p;
 BOOST_CHECK_EQUAL(p, p2);     //兩個shared_ptr必定相等
 BOOST_CHECK_EQUAL(p2.use_count(), 2);
 *p2 = 255;
 BOOST_CHECK_EQUAL(*p, 255);
 BOOST_CHECK_GT(*p, 200);
}
BOOST_AUTO_TEST_SUITE_END()

測試夾具:
 UTF中“測試夾具”的概念,它實現了自動的測試安裝和測試清理,就像是一個夾在測試案例和測試套件兩端的夾子,測試夾具不僅可以用於測試案例,也可以用於測試套件和單元測試全域。
 使用測試夾具,必須要定義一個夾具類,它只有建構函式和解構函式,用於執行測試安裝和測試清理,基本形式:
struct test_fixture_name
{
 test_fixture_name(){}
 ~test_fixture_name(){}
};
 夾具類通常是個struct,因為它被UTF用於繼承,測試套件可以使用它的所有成員,當然夾具類也可以是一個標準的class,有私人,保護和公開成員,但這樣測試套件就只能訪問夾具的保護和公開成員。
 指定測試案例和測試套件的夾具類需要使用另外兩個宏:
#define BOOST_FIXTURE_TEST_SUITE(suite_name, F)
#define BOOST_FIXTURE_TEST_CASE(test_name, F)
 替代了之前的BOOST_AUTO_TEST_CASE和BOOST_AUTO_TEST_SUITE宏,第二個參數指定了要使用的夾具類。
 可以在測試套件層級指定夾具,這樣套件內的所有子套件和測試案例都自動使用夾具類提供的安裝和清理功能,但子套件和測試案例也可以另外自己指定其他夾具,不會受上層測試套件的影響。
 全域測試夾具需要使用另一個宏BOOST_GLOBAL_FIXTURE,它定義的夾具類被應用於整個測試模組的所有測試套件--包括主測試套件。
示範:測試對象是assign庫:
//////////////////////////////////
#include <iostream>
#define BOOST_TEST_MAIN
#include <boost/test/included/unit_test.hpp>
using namespace boost;
///////////////////////////////////
#include <iostream>
#define BOOST_TEST_INCLUDED
#include <boost/test/unit_test.hpp>
#include <boost/assign.hpp>
using namespace boost;
using namespace std;

//全域測試夾具類
struct global_fixture
{
 global_fixture(){cout<<"global setup\n";}
 ~global_fixture(){cout<<"global teardown\n";}
};

//定義全域夾具
BOOST_GLOBAL_FIXTURE(global_fixture);

//測試套件夾具類
struct assign_fixture
{
 assign_fixture(){cout<<"suit setup\n";}
 ~assign_fixture(){cout<<"suit teardown\n";}
 vector<int> v;  //所有測試案例都可用的成員變數
};

//定義測試套件層級的夾具
BOOST_FIXTURE_TEST_SUITE(s_assign, assign_fixture)

BOOST_AUTO_TEST_CASE(t_assign1)   //測試+=操作符
{
 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)   //測試push_back函數
{
 using namespace boost::assign;
 push_back(v) (10)(20)(30);

 BOOST_CHECK_EQUAL(v.empty(), false);
 BOOST_CHECK_LT(v[0], v[1]);
}
BOOST_AUTO_TEST_SUITE_END()

測試日誌:
 測試日誌是單元測試在運行過程中產生的各種文本資訊,包括警告,錯誤和基本資料,預設情況下這些測試日誌都被定向到標準輸出(stdout),測試日誌不同於測試報告,後者是對測試日誌的總結.
 每條測試日誌都有一個層級,只有超過允許層級的日誌才能被輸出,UTF的日誌的層級從低到高,進階別禁止低層級的許可,但比它更進階別的日誌則不受限制。
這些記錄層級如下:
 【1】all,輸出所有的測試日誌
 【2】success,相當於all;
 【3】test_suite,僅允許運行測試套件的資訊
 【4】message:僅允許輸出使用者測試資訊(BOOST_TEST_MESSAGE);
 【5】warning,僅允許輸出警告斷言資訊(BOOST_WARN_XXX)
 【6】error:僅允許輸出CHECK,REQUIRE斷言資訊(BOOST_CHECK_XXX)
 【7】cpp_exception:僅允許輸出未捕獲的c++異常資訊。
 【8】system_error,僅允許非致命的系統錯誤。
 【9】fatal_error,僅允許輸出致命的系統錯誤
 【10】nothing;禁止任何資訊輸出.
 預設情況,UTF的記錄層級是warning,會輸出大部分單元測試相關的診斷資訊,但BOOST_TEST_MESSAGE宏由於是message層級,它的資訊不會輸出.

 記錄層級可以通過接下來介紹的單元測試程式的命令列參數改變

運行參數:
 運行時,命令列參數:
 UTF的命令列參數基本格式是:
 --arg_name=arg_value
 參數名稱和參數值都是大小寫敏感的,並且=兩邊和--右邊不能有空格
 常用的命令列參數:
 【1】run_test,指定要啟動並執行測試案例或測試套件,用斜杠(/)來訪問樹的任意節點,支援使用萬用字元*;
 【2】build_info;單元測試時輸出編譯器,STL,Boost等系統資訊,取值為yes/no;
 【3】output_format;指定輸出資訊的格式,取值為hrf(可讀格式)/xml;
 【4】log_format:指定日誌資訊的格式,取值為hrf(可讀格式)/xml;
 【5】log_level:允許輸出的記錄層級,取值為all,success,test_sutie,message,warning,error,cpp_exception,system_error,fatal_error,nothing,預設是warning;
 【6】show_progress;基於progress_display組件,顯示測試的進度,取值為yes/no,UTF不能顯示測試案例內部的進度,只能顯示已經完成的測試案例與測試案例總數的比例。
示範:
 --build_info=yes --run_test=s_assign/* --output_format=xml

函數執行監視器:
 test庫在UTF架構低層提供一個函數執行監視器類execution_monitor,它被UTF用於單元測試,但也可以被用於生產代碼,execution_monitor可以監控某個函數的執行,即使函數發生預想以外的異常,也能夠保證程式不受影響地正常運行,異常將會以一致的方式被execution_monitor處理。
定義源檔案:
#include <boost/test/impl/execution_monitor.ipp>
#include <boost/test/impl/debug.ipp>
using namespace boost;
用法:
 execution_monitor目前可以監控傳回值為int或者可轉換為int的函數,並需要使用unit_test::callback0<int>函數對象來封裝,之後成員函數execute()就可以監控執行被封裝的函數。
 execution_monitor的監控執行語句需要嵌入在一個try-catch塊裡,如果一切正常,那麼被execution_monitor監控執行的函數就像未被監控一樣運行並返回,否則,如果發生了未捕獲的異常,軟硬體signal或trap,以及vc下的assert斷言,那麼execution_monitor就會捕獲這個異常,重新拋出一個execution_monitor異常,它儲存了異常相關的資訊。
 execution_monitor不是標準庫異常,std::exception的子類,必須在catch塊明確寫出它的類型,否則execution_monitor拋出的異常不會被捕獲。
示範:
#include <iostream>
#define BOOST_TEST_INCLUDED
#include <boost/test/unit_test.hpp>
#include <boost/test/execution_monitor.hpp>
#include <boost/test/utils/basic_cstring/io.hpp>
#include <boost/assign.hpp>
using namespace boost;
using namespace std;
int f()
{
 cout<<"f execute"<<endl;
 throw "a error accoured";//拋出一個未捕獲的異常
 return 10;
}

int main //測試主函數
{
 execution_monitor em;      //聲明一個監視器對象
 try
 {
  em.execute(unit_test::callback0<int>(f));//監控執行f
 }
 catch (execution_exception& e)
 {
  cout<< "execution_exception"<<endl;
  cout<< e.what().begin()<<endl;   //輸出異常資訊
 }

 system("pause");
 return 0;
}

其他用法:
 execution_monitor還提供了p_timeout,p_auto_start_dbg等讀寫屬性用來設定監控器的行為,或者檢測記憶體泄露,但這些功能不是完全可移植的。
 execution_monitor也可以用於統一處理常式的異常,使使用者不必自己編寫錯誤處理代碼,在這種情況下,程式拋出的異常類型必須是c字串,std::string或者std::exception三者之一,才能被execution_exception所處理
示範 :定義異常類的翻譯函數,並註冊到exception_monitor中,
struct my_error
{
 int err_code;   //錯誤碼
 my_error(int ec):err_code(ec){} //建構函式
};
void translate_my_err(const my_error& e)//翻譯函數
{
 cout<<"my err = "<< e.err_code<<endl;
}
int f()
{
 cout<<"f execute."<<endl;
 throw my_error(100);
 return 0;
}

int main()
{
 execution_monitor em;
 //使用register_exception_translator函數註冊異常翻譯函數
 em.register_exception_translator<my_error>(translate_my_err);
 try
 {
  em.execute(unit_test::callback0<int>(f));
 }
 catch(const execution_exception& e)
 {
  cout<<"execution_exception"<<endl;
  cout<<e.what().begin();
 }
}

程式執行監視器:
 test庫在函數執行監視器execution_monitor的基礎上提供者執行監視器,它的目的與execution_monitor相似,監控整個程式的執行,把程式中的異常統一轉換為標準的作業系統可用的錯誤返回碼。
 程式執行監視器的用法很像minimal test,只需要包含一個標頭檔,並實現與main()具有相同簽名的cpp_main();
 #include <boost/test/included/prg_exec_monitor.hpp>
 int cpp_main(int argc, char* argv[]){...}
 注意:cpp_main()必須返回一個整數,它不同於main(),不具有預設返回0值的能力,程式執行監視器使用一個函數對象封裝了cpp_main(),將它轉換成一個返回int的無參函數對象,然後使用execution_monitor監控執行,因此它的行為基本上與execution_monitor相同,當cpp_main()發生異常或者返回非0值時,就會被捕獲,並把異常資訊輸出到螢幕上。

期望測試失敗:
 有時候需要特定的測試失敗,允許有少量的斷言不通過,這時可以使用宏BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES,它的聲明如下,
#define BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(test_name,n)
在測試套件內部使用這個宏,指定測試案例名和允許失敗的數量,例如;
BOOST_FIXTURE_TEST_SUITE(test_suit,fixture)
//允許出現兩個宣告失敗
BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(t_case1, 2)
BOOST_AUTO_TEST_CASE(t_case1)
{...}
BOOST_AUTO_TEST_SUITE_END()
 這個功能在程式還沒有完成所有模組的功能時很有用,可以先寫好單元測試代碼,使用BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES忽略未完成的功能代碼測試。

手工註冊測試案例:
 手工測試可以任意編寫測試用函數或者接受一些測試用的資料,最後只需要少量的代碼就可以註冊到UTF,實現測試代碼與註冊的分離
 手工註冊需要使用宏BOOST_TEST_CASE和BOOST_PARAM_TEST_CASE產生測試案例類,並調用framework::xxx_test_suite().add()方法

測試泛型代碼:
 UTF也能夠測試模板函數和模板類。

vc下使用test庫的一個小技巧:
 在工程選項build-event中設定post-build,加入命令:
 "$(TargetDir)\$(TargetName).exe" --result_code=no --report_level=no;
 這樣在vc編譯完成後可以立刻運行單元測試,並且在output視窗顯示出未通過的測試斷言,可以用雙擊的方式快速調轉到斷言位置,提高測試效率。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.