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窗口显示出未通过的测试断言,可以用双击的方式快速调转到断言位置,提高测试效率。