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 returnTest::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 secondsTest: always_failSuite: FailTestSuiteFile: mytest.cppLine: 62Message: "unconditional fail"CompareTestSuite: 3/3, 33% correct in 0.000005 secondsTest: compareSuite: CompareTestSuiteFile: mytest.cppLine: 89Message: 0 == 1Test: delta_compareSuite: CompareTestSuiteFile: mytest.cppLine: 100Message: delta(0.5, 0.7, 0.1)ThrowTestSuite: 2/2, 50% correct in 0.000092 secondsTest: test_throwSuite: ThrowTestSuiteFile: mytest.cppLine: 122Message: func() does not throw, expected int exceptionTest: test_throwSuite: ThrowTestSuiteFile: mytest.cppLine: 123Message: func_no_throw() does not throw, expected int exceptionTest: test_throwSuite: ThrowTestSuiteFile: mytest.cppLine: 124Message: func() does not throw, expected any exceptionTest: test_throwSuite: ThrowTestSuiteFile: mytest.cppLine: 125Message: func_no_throw() does not throw, expected any exceptionTest: test_throwSuite: ThrowTestSuiteFile: mytest.cppLine: 139Message: func_throw_int() throws an int, expected a float exceptionTest: test_throwSuite: ThrowTestSuiteFile: mytest.cppLine: 140Message: func_throw_int() throws an int, expected no exception at allTotal: 7 tests, 42% correct in 0.000101 seconds
3.4 Html格式
html格式输出截图如下: