boost的单元测试框架
boost
提供了单元测试的框架,简单易用。在项目已经用了boost时,无需多余配置,使用非常方便。
1. 简单用法
单元测试框架里有三层,第一层是TEST_MODULE
,第二层是TEST_SUITE
,第三层是TEST_CASE
。简单的例子如下:
// test.cpp
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE test_module_1
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE(test_suit1)
BOOST_AUTO_TEST_CASE(test_case1)
{
BOOST_CHECK(2 + 2 == 4);
}
BOOST_AUTO_TEST_CASE(test_case2)
{
BOOST_CHECK(2 + 2 == 5);
}
BOOST_AUTO_TEST_SUITE_END();
BOOST_AUTO_TEST_SUITE(test_suite2)
BOOST_AUTO_TEST_CASE(test_case3) {
BOOST_CHECK_EQUAL(1, 2);
}
BOOST_AUTO_TEST_SUITE_END();
编译时,需将boost的头文件和lib文件目录加入搜寻路径,并将boost_unit_test_framework加入链接库。GCC编译的配置选项大概长这个样子
g++ -o test test.cpp -Iboost_include_path -Lboost_lib_path -lboost_unit_test_framework
可以将多个test文件加入到单元测试,编译成同一个可执行文件:
// test2.cpp
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_CASE(test_case4) {
BOOST_CHECK_EQUAL(2, 2);
}
编译选项:
g++ -o test test.cpp test2.cpp -Iboost_include_path -Lboost_lib_path -lboost_unit_test_framework
但需注意几点:
#define BOOST_TEST_DYN_LINK
用来自动生成main
函数(所以不用手写),因此至多一个cpp
文件里包含该宏,否则会出现错误。- 同一个目标可执行文件,只能用一个TEST_MODULE,只在一个
cpp
文件定义#define BOOST_TEST_MODULE
即可。
2. 测试断言
测试断言即用来指定测试的行为,其基本格式为 BOOST_LEVEL_ITEM。
LEVEL有三类:
- WARN:在测试错误时,发出警告,不增加错误数量,不影响程序运行。实际用得不多。
- CHECK: 在测试错误时,增加错误数量,打印错误提示信息,但不影响程序运行。实际中用得最多。
- REQUIRE: 在测试错误时,增加错误数量,并终止测试。一般用于该错误将影响后续测试时。
ITEM有多个:
BOOST_CHECK(expr); // error when expr == false
BOOST_CHECK_EQUAL(a, b); // error when a != b
BOOST_CHECK_CLOSE(a, b, e); // error when |a-b|/min(|a|,|b|) > e
BOOST_CHECK_CLOSE_FRACTION(a, b, e); // error when |a-b|>e
BOOST_CHECK_GE/GT/LT/LE/NE(a,b) // error when a not >=/>/</<=/!= b (compare)
BOOST_CHECK_NO_THROW(a); // error when a throw error
BOOST_CHECK_THROW(a, e) // error when a not throw e,where e is an error type
3. 单元测试的初始化
boost的单元测试框架提供一个叫做FIXTURE
的框架,可让在单元测试开始前进行初始化,在结束后自动析构。它可以应用在全局、SUITE和CASE级别。
#define BOOST_TEST_MODULE example
#include <boost/test/included/unit_test.hpp>
#include <iostream>
struct GlobalFixture {
GlobalFixture():global_i(0) { std::cout << "global setup" << std::endl; }
~GlobalFixture() { std::cout << "global teardown" << std::endl; }
int global_i;
};
struct SuiteFixture {
SuiteFixture():suite_i(1) { std::cout << "suite setup" << std::endl; }
~SuiteFixture() { std::cout << "suite teardown" << std::endl; }
int suite_i;
};
struct CaseFixture {
CaseFixture():case_i(2) { std::cout << "case setup" << std::endl; }
~CaseFixture() { std::cout << "case teardown" << std::endl; }
int case_i;
};
BOOST_GLOBAL_FIXTURE(GlobalFixture);
BOOST_FIXTURE_TEST_SUITE(test_suite10, SuiteFixture);
BOOST_AUTO_TEST_CASE(test_case10) {
BOOST_CHECK_EQUAL(suite_i, 1);
suite_i = 2;
}
BOOST_AUTO_TEST_CASE(test_case11) {
BOOST_CHECK_EQUAL(suite_i, 1);
}
BOOST_AUTO_TEST_SUITE_END();
BOOST_AUTO_TEST_SUITE(test_suite11);
BOOST_FIXTURE_TEST_CASE(test_case12, CaseFixture) {
BOOST_CHECK_EQUAL(case_i, 2);
case_i = 3;
}
BOOST_FIXTURE_TEST_CASE(test_case13, CaseFixture) {
BOOST_CHECK_EQUAL(case_i, 2);
case_i = 3;
}
BOOST_AUTO_TEST_SUITE_END();
注意几点:
- Case内部可直接使用SUITE和CASE的Fixutre类内部的成员变量和函数。
- SUITE级别的Fixture是在每个CASE级别进出时初始化和析构,而不是在SUITE进出时。也即,一个定义了Fixture的 SUITE,如果该SUITE包含多个CASE,那么这个Fixture会被初始化和析构多次,而Fixture内部的变量也无法在不同case之间共用。
- 注意没有
BOOST_FIXTURE_TEST_SUITE_END
,全部用BOOST_AUTO_TEST_SUITE_END
标志一个SUITE的结束。