C++单元测试:boost.test

徐景明
2023-12-01

C++单元测试:boost.test

1) 准备

1.1) 编译boost test

cd boost_1_55_0

# On Windows
bootstrap.bat
b2 --toolset=msvc-10.0 --build-type=minimal --with-test runtime-link=static stage
# 1) --toolset=msvc-10.0: 指定编译器,这儿是VS2010。其他版本可见链接1。
# 2) --build-type=minimal: 默认,按其描述相当于设定了下述属性:
#   link=static runtime-link=shared threading=multi variant=debug,release
# 3) --with-test: 指定编译test。一旦用了'--with',就只编译指定库了。
# 4) runtime-link=static: 添加静态链接运行时库。link与runtime-link区分,可见链接2。
# 5) stage: 只编译和安装库文件,也就是不会包含头文件。

# On Linux
# 是否已预安装
ll /usr/lib/libboost*
# yum list installed boost*
./bootstrap.sh
./b2 --toolset=gcc --build-type=minimal --with-test stage
# 1) --prefix: 安装路径,默认/usr/local。
# 2) --build-type=minimal: 默认,Linux下相当于设定了下述属性:
#   link=static,shared threading=multi variant=release

# 帮助
./b2 --help
./b2 --show-libraries

参考

  1. b2 Invocation
  2. Getting Started on Windows
  3. Getting Started on Unix Variants

中文的话,可参考这两篇:

  1. Boost下载安装编译配置使用指南
  2. VS2010 编译安装boost库

链接

  1. C++ Compilers: Microsoft Visual C++
  2. link和runtime-link,搭配shared和static

1.2) 引入boost test

# On Windows,静态链接方式
"IncludePath" += boost_1_55_0
"LibraryPath" += boost_1_55_0\stage\lib
指定选项:/EHa,/MT[d]

# On Linux,动态链接方式
定义宏:BOOST_TEST_DYN_LINK
链接时:-lboost_unit_test_framework

2) 使用

官方文档Boost Test Library讲的很详细。主要是几下几方面:

2.1) Hello the testing world

test_hello.cc

#define BOOST_TEST_MODULE MyTest
#include <boost/test/unit_test.hpp>

int add( int i, int j ) { return i+j; }

BOOST_AUTO_TEST_CASE( my_test )
{
    // seven ways to detect and report the same error:
    BOOST_CHECK( add( 2,2 ) == 4 );        // #1 continues on error

    BOOST_REQUIRE( add( 2,2 ) == 4 );      // #2 throws on error

    if( add( 2,2 ) != 4 )
      BOOST_ERROR( "Ouch..." );            // #3 continues on error

    if( add( 2,2 ) != 4 )
      BOOST_FAIL( "Ouch..." );             // #4 throws on error

    if( add( 2,2 ) != 4 ) throw "Ouch..."; // #5 throws on error

    BOOST_CHECK_MESSAGE( add( 2,2 ) == 4,  // #6 continues on error
                         "add(..) result: " << add( 2,2 ) );

    BOOST_CHECK_EQUAL( add( 2,2 ), 4 );   // #7 continues on error
}

官方的例子,很简单:

  1. “BOOST_TEST_MODULE”,定义测试模块。之后再include “unit_test.hpp”。
  2. “BOOST_AUTO_TEST_CASE”,自动注册测试用例。
  3. 测试工具分为"WARN”,“CHECK"和"REQUIRE"三个等级。“CHECK"与"REQUIRE"差别为:前者即使失败,也仍然继续;后者则认为是必须的,为严重错误,直接退出当前测试。

测试工具参考,见testing tools reference

2.2) 自动注册测试套件(Test suites

用以下宏把"TEST_CASE"包起来即成:

BOOST_AUTO_TEST_SUITE(test_suite_name)
BOOST_AUTO_TEST_SUITE_END()

test_suite.cc

#define BOOST_TEST_MODULE MySuiteTest
#include <boost/test/included/unit_test.hpp>

/* test_suite1 start */
BOOST_AUTO_TEST_SUITE( test_suite1 )
// test_case1 in test_suite1
BOOST_AUTO_TEST_CASE( test_case1 )
{
    BOOST_WARN( sizeof(int) < 4 );
}
// test_case2 in test_suite1
BOOST_AUTO_TEST_CASE( test_case2 )
{
    BOOST_REQUIRE_EQUAL( 1, 2 );  // note: REQUIRE
    BOOST_FAIL( "Should never reach this line" );
}
BOOST_AUTO_TEST_SUITE_END()
/* test_suite1 end */

/* test_suite2 start */
BOOST_AUTO_TEST_SUITE( test_suite2 )
// test_case3 in test_suite2
BOOST_AUTO_TEST_CASE( test_case3 )
{
    BOOST_CHECK( true );
}
BOOST_AUTO_TEST_SUITE_END()
/* test_suite2 end */

// test_case_on_file_scope
BOOST_AUTO_TEST_CASE( test_case_on_file_scope )
{
    BOOST_CHECK( true );
}

/* test_suite2 start */
BOOST_AUTO_TEST_SUITE( test_suite2 )
// test_case4 in test_suite2
BOOST_AUTO_TEST_CASE( test_case4 )
{
    BOOST_CHECK( false );
}
BOOST_AUTO_TEST_SUITE_END()
/* test_suite2 end */
  1. 上述定义了两个"TEST_SUITE”:test_case1、test_case1在test_suite1内;test_case3、test_case4在test_suite2内。
  2. 注意test_case_on_file_scope,其上下分别是test_suite2的test_case3、test_case4。也就是测试套件可以分为多个部分,以便放在不同文件。

2.3) 使用测试夹具(Test fixtures

重复的测试数据,都可以放到一个夹具里。其模板如下:

struct <fixture-name>{
   <fixture-name>(); // setup function
   ~<fixture-name>(); // teardown function
};

然后,使用时:

  1. “BOOST_FIXTURE_TEST_CASE”,用在测试用例上。
  2. “BOOST_FIXTURE_TEST_SUITE”,用在测试套件上。这样的话,测试套件每个测试用例就不用写了。
  3. “BOOST_GLOBAL_FIXTURE”,用在全局上。

test_suite.cc

#define BOOST_TEST_MODULE MyFixtureTest
#include <boost/test/included/unit_test.hpp>
#include <iostream>

/* 3) Global fixture */
struct MyConfig {
    MyConfig() : g_i( 0 )
    {
        instance() = this;
        std::cout << "global setup\n";
    }
    ~MyConfig()
    {
        std::cout << "g_i: " << g_i << std::endl;
        std::cout << "global teardown\n";
    }
    static MyConfig *&instance();
    int g_i;
};
BOOST_GLOBAL_FIXTURE(MyConfig);

MyConfig *&MyConfig::instance()
{
    static MyConfig *s_inst = 0;
    return s_inst;
}

/* 1) Per test case fixture */
struct F {
    F() : i( 0 ) { std::cout << "setup fixture\n"; }
    ~F()         { std::cout << "teardown fixture\n"; }
    int i;
};
BOOST_FIXTURE_TEST_CASE( test_case1, F )
{
    BOOST_CHECK( i == 1 );  // failed: i == 0
    ++i;
}
BOOST_FIXTURE_TEST_CASE( test_case2, F )
{
    BOOST_CHECK_EQUAL( i, 0 );  // pass: i == 0
    ++(MyConfig::instance()->g_i);
}
BOOST_AUTO_TEST_CASE( test_case3 )
{
    BOOST_CHECK( true );
    std::cout << "g_i: " << MyConfig::instance()->g_i << std::endl;
}

/* 2) Test suite level fixture */
BOOST_FIXTURE_TEST_SUITE( test_suite1, F )
BOOST_AUTO_TEST_CASE( test_case1 )
{
    BOOST_CHECK( i == 1 );  // failed: i == 0
    ++i;
}
BOOST_AUTO_TEST_CASE( test_case2 )
{
    BOOST_CHECK_EQUAL( i, 0 );  // pass: i == 0
    ++(MyConfig::instance()->g_i);
}
BOOST_AUTO_TEST_SUITE_END()
  1. 输出会有四组"setup fixture"与"teardown fixture”,每个用到的测试用例下各自一份。
  2. “global setup"与"global teardown"则分别于头尾,只有一个实例。官方文档没看到如何访问其成员,这里用了单例方式来处理。

3) 总结

本文主要介绍了boost单元测试框架的使用。


附1:样例工程btest_start

下载:btest_start.zip

目录树如下:

btest_start/
├─build/
│  ├─btest_start-gcc.cbp   # for gnu gcc
│  └─btest_start-msvc.cbp  # for msvc 2010
├─src/
├─third_party/
│  └─boost_1_55_0/
└─tools/

C::B工程,boost_1_55_0/目录Windows上配置时用到了。

 类似资料: