CPPTest实例分析(C++ Test)

1 概述

CppTest是一个可移植、功能强大但简单的单元测试框架,用于处理C++中的自动化测试。重点在于可用性和可扩展性。支持多种输出格式,并且可以轻松添加新的输出格式。

CppTest下载地址:下载地址1下载地址2

下面结合实例分析下CppTest如何使用。

2 实例

利用CppTest编写单元测试用例需要从Suite类派生(这里Suite翻译为组),CppTest所有类型命名空间是Test。

实例选择CppTest源码中自带的例子。

2.1 无条件失败测试用例

测试用例组定义如下:

cpp 复制代码
#include "cpptest.h"

// Tests unconditional fail asserts
//
class FailTestSuite : public Test::Suite
{
public:
    FailTestSuite()
    {
        TEST_ADD(FailTestSuite::success)
        TEST_ADD(FailTestSuite::always_fail)
    }
private:
    void success() {}

    void always_fail()
    {
        // This will always fail
        //
        TEST_FAIL("unconditional fail");
    }
};

说明:

  • 类型FailTestSuite从Test::Suite派生
  • 在构造函数中通过宏TEST_ADD增加两个测试用例success和always_fail
  • success函数什么也不作做所以是成功的
  • always_fail函数调用TEST_FAIL宏报告一个无条件失败。

2.2 比较测试用例

测试用例组定义如下:

cpp 复制代码
class CompareTestSuite : public Test::Suite
{
public:
    CompareTestSuite()
    {
        TEST_ADD(CompareTestSuite::success)
        TEST_ADD(CompareTestSuite::compare)
        TEST_ADD(CompareTestSuite::delta_compare)
    }
private:
    void success() {}

    void compare()
    {
        // Will succeed since the expression evaluates to true
        //
        TEST_ASSERT(1 + 1 == 2)

        // Will fail since the expression evaluates to false
        //
        TEST_ASSERT(0 == 1);
    }

    void delta_compare()
    {
        // Will succeed since the expression evaluates to true
        //
        TEST_ASSERT_DELTA(0.5, 0.7, 0.3);

        // Will fail since the expression evaluates to false
        //
        TEST_ASSERT_DELTA(0.5, 0.7, 0.1);
    }
};

说明:

  • 类型CompareTestSuite从Test::Suite派生
  • 在构造函数中通过宏TEST_ADD增加三个测试用例success, compare和delta_compare
  • success函数什么也不作做所以是成功的
  • compare函数调用TEST_ASSERT宏判断条件是否成立,如果条件失败报告错误。
  • delta_compare函数调用TEST_ASSERT_DELTA宏判断条件是否成立,第一次调用满足0.7 > (0.5 - 0.3) && 0.7 < (0.5 + 0.3)所以是成功的,第二次调用不满足0.7 > (0.5 - 0.1) && 0.7 < (0.5 + 0.1)所以报告失败。

2.3 异常测试用例

测试用例组定义如下:

cpp 复制代码
class ThrowTestSuite : public Test::Suite
{
public:
    ThrowTestSuite()
    {
        TEST_ADD(ThrowTestSuite::success)
        TEST_ADD(ThrowTestSuite::test_throw)
    }
private:
    void success() {}

    void test_throw()
    {
        // Will fail since the none of the functions throws anything
        //
        TEST_THROWS_MSG(func(), int, "func() does not throw, expected int exception")
        TEST_THROWS_MSG(func_no_throw(), int, "func_no_throw() does not throw, expected int exception")
        TEST_THROWS_ANYTHING_MSG(func(), "func() does not throw, expected any exception")
        TEST_THROWS_ANYTHING_MSG(func_no_throw(), "func_no_throw() does not throw, expected any exception")

        // Will succeed since none of the functions throws anything
        //
        TEST_THROWS_NOTHING(func())
        TEST_THROWS_NOTHING(func_no_throw())

        // Will succeed since func_throw_int() throws an int
        //
        TEST_THROWS(func_throw_int(), int)
        TEST_THROWS_ANYTHING(func_throw_int())

        // Will fail since func_throw_int() throws an int (not a float)
        //
        TEST_THROWS_MSG(func_throw_int(), float, "func_throw_int() throws an int, expected a float exception")
        TEST_THROWS_NOTHING_MSG(func_throw_int(), "func_throw_int() throws an int, expected no exception at all")
    }

    void func() {}
    void func_no_throw() {}
    void func_throw_int() { throw 13; }
};

说明:

  • 类型ThrowTestSuite从Test::Suite派生
  • 在构造函数中通过宏TEST_ADD增加两个测试用例success和test_throw
  • success函数什么也不作做所以是成功的
  • 函数func和func_no_throw不会抛异常
  • 函数func_throw_int抛int类型异常13
  • test_throw调用6种宏测试函数调用异常,_MSG后缀版本指定异常文本。
    • TEST_THROWS_MSG 宏测试函数调用如果抛出指定异常则成功,否则失败
    • TEST_THROWS 宏测试函数调用如果抛出指定异常则成功,否则失败
    • TEST_THROWS_ANYTHING_MSG 宏测试函数调用如果抛出任意类型异常则成功,否则失败
    • TEST_THROWS_ANYTHING 宏测试函数调用如果抛出任意类型异常则成功,否则失败
    • TEST_THROWS_NOTHING 宏测试函数调用不抛异常则成功,否则失败
    • TEST_THROWS_NOTHING_MSG 宏测试函数调用不抛异常则成功,否则失败

2.4 测试用例运行

前面定义了三个测试用例组FailTestSuite,CompareTestSuite和ThrowTestSuite,下面将三个测试用例组加到测试程序中。

2.4.1 main

cpp 复制代码
main(int argc, char* argv[])
{
    try
    {
        // Demonstrates the ability to use multiple test suites
        //
        Test::Suite ts;
        ts.add(unique_ptr<Test::Suite>(new FailTestSuite));
        ts.add(unique_ptr<Test::Suite>(new CompareTestSuite));
        ts.add(unique_ptr<Test::Suite>(new ThrowTestSuite));

        // Run the tests
        //
        unique_ptr<Test::Output> output(cmdline(argc, argv));
        ts.run(*output, true);

        Test::HtmlOutput* const html = dynamic_cast<Test::HtmlOutput*>(output.get());
        if (html)
            html->generate(cout, true, "MyTest");
    }
    catch (...)
    {
        cout << "unexpected exception encountered\n";
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

说明:

  • 定义测试用例组ts
  • 通过ts函数add将FailTestSuite,CompareTestSuite和ThrowTestSuite加到测试用例组ts中
  • 定义测试输出对象outuput
  • 调用ts函数run运行测试用例,run第二参数cont_after_fail指示出错后是否接着执行,这里设置为true表示出错后接着执行。
  • 如果output是html类型,最后将html内容输出标准输出cout.

2.4.2 usage/cmdline

CppTest的输出格式默认支持四种格式:

  • Compiler 编译器格式
  • Html 网页格式
  • TextTerse 简约文本格式
  • TextVerbose 详细文本格式

可以派生新的输出格式:

  • 从Test::Output类型派生新的输出格式。
  • 从Test::CollectorOutput类型派生新的收集器输出格式。收集器输出格式整个测试用例运行完毕后再输出,HtmlOutput就是收集器输出格式。

下面代码从命令参数获取输出格式:

cpp 复制代码
static void
usage()
{
    cout << "usage: mytest [MODE]\n"
         << "where MODE may be one of:\n"
         << "  --compiler\n"
         << "  --html\n"
         << "  --text-terse (default)\n"
         << "  --text-verbose\n";
    exit(0);
}

static unique_ptr<Test::Output>
cmdline(int argc, char* argv[])
{
    if (argc > 2)
        usage(); // will not return

    Test::Output* output = 0;

    if (argc == 1)
        output = new Test::TextOutput(Test::TextOutput::Verbose);
    else
    {
        const char* arg = argv[1];
        if (strcmp(arg, "--compiler") == 0)
            output = new Test::CompilerOutput;
        else if (strcmp(arg, "--html") == 0)
            output =  new Test::HtmlOutput;
        else if (strcmp(arg, "--text-terse") == 0)
            output = new Test::TextOutput(Test::TextOutput::Terse);
        else if (strcmp(arg, "--text-verbose") == 0)
            output = new Test::TextOutput(Test::TextOutput::Verbose);
        else
        {
            cout << "invalid commandline argument: " << arg << endl;
            usage(); // will not return
        }
    }

    return unique_ptr<Test::Output>(output);
}

函数说明:

  • usage 输出命令参数用法
  • cmdline 根据命令参数构造不同类型输出格式。

3 运行

3.1 Compiler输出

$ ./mytest --compiler
mytest.cpp:62: "unconditional fail"
mytest.cpp:89: 0 == 1
mytest.cpp:100: delta(0.5, 0.7, 0.1)
mytest.cpp:122: func() does not throw, expected int exception
mytest.cpp:123: func_no_throw() does not throw, expected int exception
mytest.cpp:124: func() does not throw, expected any exception
mytest.cpp:125: func_no_throw() does not throw, expected any exception
mytest.cpp:139: func_throw_int() throws an int, expected a float exception
mytest.cpp:140: func_throw_int() throws an int, expected no exception at all

3.2 TextTerse输出

$ ./mytest --text-terse
FailTestSuite: 2/2, 50% correct in 0.000005 seconds
CompareTestSuite: 3/3, 33% correct in 0.000005 seconds
ThrowTestSuite: 2/2, 50% correct in 0.000093 seconds
Total: 7 tests, 42% correct in 0.000103 seconds

3.3 TextVerbose输出

$ ./mytest --text-verbose
FailTestSuite: 2/2, 50% correct in 0.000004 seconds
        Test:    always_fail
        Suite:   FailTestSuite
        File:    mytest.cpp
        Line:    62
        Message: "unconditional fail"

CompareTestSuite: 3/3, 33% correct in 0.000005 seconds
        Test:    compare
        Suite:   CompareTestSuite
        File:    mytest.cpp
        Line:    89
        Message: 0 == 1

        Test:    delta_compare
        Suite:   CompareTestSuite
        File:    mytest.cpp
        Line:    100
        Message: delta(0.5, 0.7, 0.1)

ThrowTestSuite: 2/2, 50% correct in 0.000092 seconds
        Test:    test_throw
        Suite:   ThrowTestSuite
        File:    mytest.cpp
        Line:    122
        Message: func() does not throw, expected int exception

        Test:    test_throw
        Suite:   ThrowTestSuite
        File:    mytest.cpp
        Line:    123
        Message: func_no_throw() does not throw, expected int exception

        Test:    test_throw
        Suite:   ThrowTestSuite
        File:    mytest.cpp
        Line:    124
        Message: func() does not throw, expected any exception

        Test:    test_throw
        Suite:   ThrowTestSuite
        File:    mytest.cpp
        Line:    125
        Message: func_no_throw() does not throw, expected any exception

        Test:    test_throw
        Suite:   ThrowTestSuite
        File:    mytest.cpp
        Line:    139
        Message: func_throw_int() throws an int, expected a float exception

        Test:    test_throw
        Suite:   ThrowTestSuite
        File:    mytest.cpp
        Line:    140
        Message: func_throw_int() throws an int, expected no exception at all

Total: 7 tests, 42% correct in 0.000101 seconds

3.4 Html格式

html格式输出截图如下:

相关推荐
小c君tt4 分钟前
MFC中 error C2440错误分析及解决方法
c++·mfc
测试界的酸菜鱼4 分钟前
C# NUnit 框架:高效使用指南
开发语言·c#·log4j
GDAL4 分钟前
lua入门教程 :模块和包
开发语言·junit·lua
李老头探索5 分钟前
Java面试之Java中实现多线程有几种方法
java·开发语言·面试
CSXB997 分钟前
三十四、Python基础语法(文件操作-上)
开发语言·python·功能测试·测试工具
web Rookie26 分钟前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
很楠不爱37 分钟前
Qt——窗口
开发语言·qt
yi碗汤园38 分钟前
【一文了解】C#基础-集合
开发语言·前端·unity·c#
木向38 分钟前
leetcode92:反转链表||
数据结构·c++·算法·leetcode·链表
阿阿越40 分钟前
算法每日练 -- 双指针篇(持续更新中)
数据结构·c++·算法