CPPTest实例分析(C++ Test)

1 概述

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

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

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

2 实例

利用CppTest编写单元测试用例需要从Suite类派生(这里Suite翻译为组),CppTest所有类型命名空间是Test。
实例选择CppTest源码中自带的例子。

2.1 无条件失败测试用例

测试用例组定义如下:

#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 比较测试用例

测试用例组定义如下:

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 异常测试用例

测试用例组定义如下:

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

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就是收集器输出格式。

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

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格式输出截图如下:
html格式输出截图

  • 20
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C++ 的测试框架通常会使用桩函数(Stub)来模拟被测对象的行为,以便在测试中进行隔离和控制。对于一些常见的函数,cpptest 可以自动生成桩函数,从而简化测试的编写过程。下面是 cpptest 如何自动生成桩函数的示例: 假设我们有一个计算器类 Calculator,其中包含一个 `add()` 方法用于计算两个整数的和。我们想要测试这个方法,但是它依赖于另外一个类的方法,因此我们需要使用桩函数来模拟这个方法的行为。 ```c++ class Calculator { public: Calculator(Adder* adder) : adder_(adder) {} int add(int a, int b) { return adder_->add(a, b); } private: Adder* adder_; }; class Adder { public: virtual ~Adder() {} virtual int add(int a, int b) = 0; }; class RealAdder : public Adder { public: int add(int a, int b) override { return a + b; } }; ``` 在使用 cpptest 进行测试时,我们可以使用 `CPPTEST_AUTO_STUB` 宏来自动生成桩函数。这个宏会根据被测函数的参数类型和返回值类型自动生成一个桩函数,并且将其添加到测试代码中。 ```c++ TEST(CalculatorTest, AddTest) { // 自动创建桩函数 CPPTEST_AUTO_STUB(int, Adder::add, (int a, int b), (a, b), (0)); // 模拟 Adder::add() 方法 Adder* adder = new AdderStub(); EXPECT_CALL(*adder, add(2, 3)).WillOnce(Return(5)); // 测试 Calculator::add() 方法 Calculator calculator(adder); EXPECT_EQ(calculator.add(2, 3), 5); } ``` 在这个示例中,我们使用 `CPPTEST_AUTO_STUB` 宏来自动生成 Adder::add() 方法的桩函数,这个桩函数的返回值类型为 int,参数类型为两个 int 类型的参数。在测试中,我们模拟了 Adder::add() 方法的行为,并且测试了 Calculator::add() 方法的正确性。 总的来说,使用 cpptest 自动生成桩函数可以简化测试代码的编写过程,提高测试的效率和可靠性。但是需要注意的是,自动生成的桩函数可能无法满足所有的测试需求,需要在实际使用中加以验证和修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flysnow010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值