C++ (boost) 单元测试

C++ (boost) 单元测试

C++ boost 单元测试

[TOC]


基本概念

Boost test库提供了一个用于单元测试的基于命令行界面的测试套件UTF:Unit Test Framework,具有单元测试、检测内存泄露、监控程序运行的功能。

测试模块

  1. 测试安装
  2. 测试主体:测试主体是测试的模块的实际运行部分,由测试用例测试套件组成的测试树形成
  3. 测试清理
  4. 测试运行器

测试用例

测试用例是一个包含多个测试断言的函数;是可以被独立执行测试的最小单元。

测试套件

测试套件是测试用例的容器,可以嵌套,包含一个或多个测试用例,将多个测试用例分组管理,共享安装、清理代码。

测试夹具(test fixture)

测试安装和测试清理好比c++中的构造函数和析构函数,“测试夹具”实现了自动的测试安装和测试清理。

超轻量及测试lightweight_test

在头文件中定义,他提供三个最简单的测试断言

BOOST_TEST      //相当于BOOST_CHECK,断言表达式成立
BOOST_ERROR     //直接断言失败,输出一条错误信息
BOOST_TEST_EQ   //相当于BOOST_CHECK_EQUAL,断言两个表达式相等

Boost最小化测试套件 minimal test

boost提供的最简单的测试套件,有基本的测试断言,适合简单测试

该套件在头文件中

#include 

定义,使用时只包含这个头文件就可以了,不需要链接其他的库,非常方便。在这个头文件中已经定义了一个mian()函数,我们不需要在写main()函数了,只需要实现一个test_main(int argc, char *argv[])就可以了。这个头文件中定义了四个断言宏,可以供我们使用。

BOOST_CHECK(predicate)      //断言表达式通过,如不通过不影响程序继续执行
BOOST_REQUIRE(predicate)    //断言表达式必须通过,如不通过程序终止
BOOST_ERROR(message)        // 给出一个错误信息,程序继续执行
BOOST_FAIL(message)         // 给出一个错误信息,程序终止执行

下面是一个小栗子:

#include "boost/test/minimal.hpp"
#include "boost/format.hpp"
#include "iostream"

int test_main(int argc, char *argv[])           // 测试主函数,不需要在定义main()
{
    using namespace boost;
    format fmt("%d-%d");

    BOOST_CHECK(fmt.size() == 0);               // 验证fmt对象初始化,不通过继续执行
    
    fmt % 12 % 34;
    
    BOOST_REQUIRE(fmt.str() == "12-34");        // 验证结果,不通过则不予执行
    
    BOOST_ERROR("演示一条错误信息");                // 打印一条错误信息,继续执行

    fmt.clear();
    fmt % 12;
    try {
        std::cout << fmt;
    }
    catch (...) {
        BOOST_FAIL("致命错误,测试终止");            // 给出一个错误信息,终止执行
    }
    
    return 0;
}

程序输出:

boost_test.cpp(9): test fmt.size() == 0 failed in function: 'int test_main(int, char **)'
boost_test.cpp(12): 演示一条错误信息 in function: 'int test_main(int, char **)'
boost_test.cpp(20): 致命错误,测试终止 in function: 'int test_main(int, char **)'

总结,minimal test方便简单,但功能有限,适用于单元测试的演示,或者较小的程序段。

UTF测试断言

UTF中的测试断言:BOOST_LEVEL_ITEM

LEVEL WARN 警告级,不增加错误数量,不影响程序运行
CHECK 检查级别,增加错误数量,不影响程序运行
REQUIRE 最高级别,增加错误数量,程序终止运行
ITEM EQUAL/CLOSE 测试相等性
GE/GT/LT/LE/NE 测试不等性
(NO_)THROW 是否抛出异常
MESSAGE 测试信息
... ...

组合出来就是如

BOOST_CHECK_EQUAL(l, r)
BOOST_REQUIRE_GE(l, r)

测试实例

举个栗子:

#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK
#include 
#include 
using namespace boost;

// 开始测试套件s_smart_ptr
BOOST_AUTO_TEST_SUITE(s_smart_ptr)

// 测试用例1:t_scoped_ptr
BOOST_AUTO_TEST_CASE(t_scoped_ptr)
{
    scoped_ptr p(new int(874));
    BOOST_CHECK(p);                     // 测试指针p的可用性
    BOOST_CHECK_EQUAL(*p, 875);         // 测试p解引用的值
 
    p.reset();
    BOOST_CHECK(p == 0);                // 测试p为空
}

// 测试用例2:t_shared_ptr
BOOST_AUTO_TEST_CASE(t_shared_ptr)
{
    shared_ptr p(new int(100));
 
    BOOST_CHECK(p);
    BOOST_CHECK_EQUAL(*p, 100);
    BOOST_CHECK_EQUAL(p.use_count(), 1);
    shared_ptr p2 = p;
    BOOST_CHECK_EQUAL(p, p2);
    BOOST_CHECK_EQUAL(p2.use_count(), 2);
 
    *p2 = 255;
    BOOST_CHECK_EQUAL(*p, 255);
    BOOST_CHECK_GT(*p, 200);
}

// 结束测试套件
BOOST_AUTO_TEST_SUITE_END()

关于#define BOOST_TEST_DYN_LINK,如果不加的话会出现下面的错误:

Undefined symbols for architecture x86_64:
  "_main", referenced from:
     implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

编译时同时需要链接-lboost_unit_test_framework

测试夹具

前面说测试夹具就好比c++的构造函数和析构函数,也可以理解为在执行测试之前设置一个环境,在测试完成时清除它。

看两个栗子吧:

#define BOOST_TEST_MODULE example
#include 
#include 

struct F {
    F():i(0) { std::cout << "setup" << std::endl; }
    ~F() { std::cout << "teardown" << std::endl; }

    int i;
};

BOOST_AUTO_TEST_SUITE( test )

BOOST_FIXTURE_TEST_CASE( test_case1, F ) {
    BOOST_CHECK( i == 1 );
    ++i;
}

BOOST_AUTO_TEST_CASE( test_case2 ) {
    BOOST_REQUIRE( 2 > 1 );
}

BOOST_AUTO_TEST_CASE( test_case3 ) {
    int i = 1;
    BOOST_CHECK_EQUAL( i, 1 );
    ++i;
}

BOOST_AUTO_TEST_SUITE_END()

输出结果是:

Running 3 test cases...
setup
boost_test.cpp:22: error in "test_case1": check i == 1 failed
teardown

*** 1 failure detected in test suite "Master Test Suite"

另一个栗子:

#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK
#include 
#include 
#include 
using namespace std;
using namespace boost;

// 全局测试夹具类
struct global_fixture {
    global_fixture() {cout << "global setup" << endl;}
    ~global_fixture() {cout << "global teardown" << endl;}
};

// 定义全局夹具
BOOST_GLOBAL_FIXTURE(global_fixture);

// 测试套件夹具类
struct assign_fixture {
    assign_fixture() {cout << "suit setup" << endl;}
    ~assign_fixture() {cout << "suit teardown" << endl;}

    std::vector 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) {
    using namespace boost::assign;

    push_back(v)(11)(22)(33);
    BOOST_CHECK_EQUAL(v.empty(), false);
    BOOST_CHECK_LT(v[0], v[1]);
}

BOOST_AUTO_TEST_SUITE_END()

后一个栗子的输出是

global setup
Running 2 test cases...
suit setup
suit teardown
suit setup
suit teardown
global teardown

你可能感兴趣的:(C++ (boost) 单元测试)