1 概述
CppTest是一个可移植、功能强大但简单的单元测试框架,用于处理C++中的自动化测试。重点在于可用性和可扩展性。支持多种输出格式,并且可以轻松添加新的输出格式。
下面结合实例分析下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格式输出截图如下: