单元测试已经越来越成为程序员工作密不可分的一部分了。在 C++ 里,我们当然也是可以很方便地进行单元测试的。今天,我就来介绍两个单元测试库:一个是 Boost.Test [1],一个是 Catch2 [2]。
Boost.Test
单元测试库有很多,我选择 Boost 的原因我在上一讲已经说过:“如果我需要某个功能,在标准库里没有,在 Boost 里有,我会很乐意直接使用 Boost 里的方案,而非另外去查找。”再说,Boost.Test 提供的功能还挺齐全的,我需要的都有了。作为开胃小菜,我们先看一个单元测试的小例子:
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <stdexcept>
void test(int n)
{
if (n == 42) {
return;
}
throw std::runtime_error(
"Not the answer");
}
BOOST_AUTO_TEST_CASE(my_test)
{
BOOST_TEST_MESSAGE("Testing");
BOOST_TEST(1 + 1 == 2);
BOOST_CHECK_THROW(
test(41), std::runtime_error);
BOOST_CHECK_NO_THROW(test(42));
int expected = 5;
BOOST_TEST(2 + 2 == expected);
BOOST_CHECK(2 + 2 == expected);
}
BOOST_AUTO_TEST_CASE(null_test)
{
}
我们从代码里可以看到:
我们在包含单元测试的头文件之前定义了 BOOST_TEST_MAIN。如果编译时用到了多个源文件,只有一个应该定义该宏。多文件测试的时候,我一般会考虑把这个定义这个宏加包含放在一个单独的文件里(只有两行)。
我们用 BOOST_AUTO_TEST_CASE 来定义一个测试用例。一个测试用例里应当有多个测试语句(如 BOOST_CHECK)。
我们用 BOOST_CHECK 或 BOOST_TEST 来检查一个应当成立的布尔表达式(区别下面会讲)。
我们用 BOOST_CHECK_THROW 来检查一个应当抛出异常的语句。
我们用 BOOST_CHECK_NO_THROW 来检查一个不应当抛出异常的语句。
如 [第 21 讲] 所述,我们可以用下面的命令行来进行编译:
MSVC:cl /DBOOST_TEST_DYN_LINK /EHsc /MD test.cpp
GCC:g++ -DBOOST_TEST_DYN_LINK test.cpp -lboost_unit_test_framework
Clang:clang++ -DBOOST_TEST_DYN_LINK test.cpp -lboost_unit_test_framework
运行结果如下图所示:
我们现在能看到 BOOST_CHECK 和 BOOST_TEST 的区别了。后者是一个较新加入 Boost.Test 的宏,能利用模板技巧来输出表达式的具体内容。但在某些情况下,BOOST_TEST 试图输出表达式的内容会导致编译出错,这时可以改用更简单的 BOOST_CHECK。
不管是 BOOST_CHECK