轻松使用Boost.test单元测试框架
Boost.test单元测试框架
Boost.test提供了一套方便进行单元测试的框架,由于不是仅头文件的库,使用时需要链接一下相关的库。
find_package(Boost REQUIRED COMPONENTS system unit_test_framework test_exec_monitor CONFIG)
target_link_libraries(demo
PRIVATE Boost::unit_test_framework
PRIVATE Boost::test_exec_monitor
)
常使用下列头文件:
#include <boost/test/unit_test.hpp>
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/data/test_case.hpp>
#include <boost/test/results_collector.hpp>
在每个测试的cpp文件最开始需要使用宏BOOST_TEST_MODULE定义一个模块名称,比如
#define BOOST_TEST_MODULE MyTestModule
...
Boost.test依赖这个宏识别不同的测试模块和控制测试套件的自动注册与执行。
测试用例
Boost的单元测试提供了BOOST_AUTO_TEST_CASE用于开启单元测试,使用方法如下:
BOOST_AUTO_TEST_CASE(my_test_case) {
int a = 1 + 1;
BOOST_TEST(a == 2);
}
测试套件
Boost.test使用BOOST_AUTO_TEST_SUITE(my_suite)开启一个测试套件,使用BOOST_AUTO_TEST_SUITE_END()标识一个测试套件结束。套件的测试用例写在一组宏的中间
OOST_AUTO_TEST_SUITE(my_suite)
BOOST_AUTO_TEST_CASE(condition1) {
BOOST_TEST(2 * 3 == 6);
}
BOOST_AUTO_TEST_CASE(condition2) {
BOOST_TEST(3 - 2 == 1);
}
BOOST_AUTO_TEST_SUITE_END()
测试夹具
Boost.test支持测试夹具,即可以声明一个类,测试用例可以直接使用类中的方法和成员变量。Boost.test支持三类测试夹具,全局夹具,套件夹具和用例夹具:
- 全局夹具:全局夹具只会在程序开始和结束时被执行一次,可以用于程序数据的初始化和释放,初始化的逻辑写在全局夹具的构造函数中,释放逻辑写在全局夹具的析构函数中。使用宏
BOOST_GLOBAL_FIXTURE注册全局夹具; - 用例夹具:用例夹具就是仅供单个测试用例使用的夹具,在用例开始时构造,在用例结束时析构,使用宏
BOOST_FIXTURE_TEST_CASE声明,第一个参数是用例名称,第二个参数是夹具类; - 套件夹具:套件夹具可以适用于套件中的所有用例。在每个用例开始时构造,在用例结束时析构,使用宏
BOOST_FIXTURE_TEST_SUITE绑定套件和夹具类,然后和普通测试套件一样,使用宏BOOST_AUTO_TEST_SUITE_END标识套件结束,套件中的每个用例可以使用宏BOOST_AUTO_TEST_CASE定义,不需要再指定夹具,会默认绑定。
struct MyGlobFixture {
int number;
MyGlobFixture() : number(42) { std::cout << "myglobfixture construct\n"; }
~MyGlobFixture() { std::cout << "myglobfixture destory\n"; }
};
BOOST_GLOBAL_FIXTURE(MyGlobFixture);
struct MyCaseFixture {
int value;
MyCaseFixture() : value(42) { std::cout << "mygcasefixture construct\n"; }
~MyCaseFixture() { std::cout << "mycasefixture destory\n"; }
};
BOOST_FIXTURE_TEST_CASE(fixture_case, MyCaseFixture) {
BOOST_CHECK(value == 42);
}
struct MyFixture {
int value;
MyFixture() : value(42) { std::cout << "myfixture construct\n"; }
~MyFixture() { std::cout << "myfixture destory\n"; }
};
BOOST_FIXTURE_TEST_SUITE(my_fixture_test_suite, MyFixture)
BOOST_AUTO_TEST_CASE(condition1) {
BOOST_TEST(value == 42);
}
BOOST_AUTO_TEST_CASE(condition2) {
value = 13;
BOOST_TEST(value == 13);
}
BOOST_AUTO_TEST_SUITE_END();
数据驱动测试(参数化测试)
Boost.test支持数据驱动的测试模式(参数化测试),使用BOOST_DATA_TEST_CASE宏定义一个参数化测试用例,支持在第二个参数中传入vector或tuple等容器,程序在执行时,会为容器中的每个元素创建一个测试用例。
BOOST_DATA_TEST_CASE(my_data_test, boost::unit_test::data::xrange(1, 5), x) {
BOOST_CHECK(x + x == 2 * x);
}
BOOST_DATA_TEST_CASE_F(MyFixture, my_data_test_fixture, boost::unit_test::data::make({1, 2, 3}),
x) {
BOOST_TEST(value + x == 42 + x);
}
BOOST_DATA_TEST_CASE(my_complex_data_test,
boost::unit_test::data::make(std::make_tuple(1, "apple"),
std::make_tuple(2, "banana"),
std::make_tuple(3, "cherry")),
seq, fruit) {
BOOST_CHECK(seq < 2 || fruit == "cherry");
}
Boost.test在boost::unit_test::data命名空间中提供了一个make方法,方便数据驱动测试用例的编写。
所有的数据驱动测试用例都可以被嵌套在套件中使用。
自定义测试观察者
Boost.test中使用观察者模式获取测试结果数据,默认定义了一个单例的results_collector类,如果需要自定义测试结果数据处理的话,就需要写一个boost::unit_test::test_observer派生类。
#define BOOST_TEST_NO_MAIN
class MyObserver : public boost::unit_test::test_observer {
public:
void test_unit_finish(boost::unit_test::test_unit const& test, unsigned long elapsed) override {
const auto& result = boost::unit_test::results_collector.results(test.p_id);
std::cout << "Test Unit Suite Name: " << test.p_name.value << " | "
<< "Time: " << elapsed << " | Status: "
<< (result.result_code() == boost::exit_success ? "pass" : "failure")
<< std::endl;
}
};
bool init_test() {
static MyObserver myobserver;
boost::unit_test::framework::register_observer(myobserver);
return true;
}
int main(int argc, char** argv) {
return boost::unit_test::unit_test_main(init_test, argc, argv);
}
如果需要使用自定义的观察者,就得自己重新定义main函数,在main函数中调用boost::unit_test::unit_test_main初始化测试框架,这个函数需要传入一个自定义的初始化函数init_test,我们需要在这个函数中调用框架的方法boost::unit_test::framework::register_observer将自定义的观察者注册到框架中。
另外,如果自己编写main函数,需要在所有cpp文件的最开头定义BOOST_TEST_NO_MAIN宏,否则Boost.test会查找到自己的main函数,编译时报重定义错误。
输出测试报告
使用Boost.test框架的单元测试程序,可以在程序启动时添加--report_level=all,--log_format=XML,--log_sink=test_result.xml参数,用于控制单元测试报告的输出:
- report_level: 控制输出报告的日志等级,可设置为all、detailed、short、no;
- log_format: 控制输出报告的格式,支持XML、HRF和JUNIT三种格式;
- log_sink: 指定报告输出位置。
虽然Boost.test本身不支持代码覆盖率统计,但可以结合Gcov/Lcov工具实现,在编译时添加-fprofile-arcs -ftest-coverage选项,然后运行测试完通过扩展工具生成覆盖率报告。

浙公网安备 33010602011771号