在 CppUnit 中,一个或一组测试用例的测试对象被称为 Fixture。Fixture 就是被测试的目标,可能是一个对象或者一组相关的对象,甚至一个函数。
有了被测试的fixture,就可以对这个 fixture 的某个功能、某个可能出错的流程编写测试代码,这样对某个方面完整的测试被称为TestCase(测试用例)。
通常写一个 TestCase 的步骤包括:
1) 对 fixture 进行初始化,及其他初始化操作,比如:生成一组被测试的对象,初始化值;
2) 按照要测试的某个功能或者某个流程对 fixture 进行操作;
3) 验证结果是否正确;
4) 对 fixture 的及其他的资源释放等清理工作。
对 fixture 的多个测试用例,通常(1)、(4)部分代码都是相似的,CppUnit在很多地方引入了setUp和tearDown虚函数。可以在 setUp 函数里完成(1)初始化代码,而在 tearDown 函数中完成(4)代码。具体测试用例函数中只需要完成(2)、(3)部分代码即可,运行时 CppUnit 会自动为每个测试用例函数运行 setUp,之后运行 tearDown,这样测试用例之间就没有交叉影响。
撰写TestCase必须注意以下几点:
l 可以自动执行,不用人手操作
l 自动返回测试结果
l 绝对的独立,不能与其他TestCase有任何联系。就算测试同一个函数的不同功能也需要分开。每个TestCase可以说是一个孤岛
对 fixture 的所有测试用例可以被封装在一个 CppUnit::TestFixture 的子类(命名惯例是[ClassName]Test)中。然后定义这个fixture 的 setUp 和 tearDown 函数,为每个测试用例定义一个测试函数(命名惯例是 testXXX)。下面是个简单的例子:
classMathTest : public CppUnit::TestFixture { protected: intm_value1, m_value2; public: MathTest() {} // 初始化函数 voidsetUp () { m_value1 = 2; m_value2 = 3; } // 测试加法的测试函数 voidtestAdd () { // 步骤(2),对 fixture 进行操作 intresult = m_value1 + m_value2; // 步骤(3),验证结果是否争取 CPPUNIT_ASSERT( result == 5 ); } // 没有什么清理工作没有定义 tearDown. }
|
在测试函数中对执行结果的验证成功或者失败直接反应这个测试用例的成功和失败。CppUnit 提供了多种验证成功失败的方式:
CPPUNIT_ASSERT(condition) // 确信condition为真 CPPUNIT_ASSERT_MESSAGE(message, condition) // 当condition为假时失败, 并打印message CPPUNIT_FAIL(message) // 当前测试失败, 并打印message CPPUNIT_ASSERT_EQUAL(expected, actual) // 确信两者相等 CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual) // 失败的同时打印message CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta) // 当expected和actual之间差大于delta时失败
|
要把对 fixture 的一个测试函数转变成一个测试用例,需要生成一个 CppUnit::TestCaller 对象。而最终运行整个应用程序的测试代码的时候,可能需要同时运行对一个 fixture 的多个测试函数,甚至多个 fixture 的测试用例。CppUnit 中把这种同时运行的测试案例的集合称为 TestSuite。而 TestRunner 则运行测试用例或者 TestSuite,具体管理所有测试用例的生命周期。目前提供了 3 类TestRunner,包括:
CppUnit::TextUi::TestRunner // 文本方式的TestRunner CppUnit::QtUi::TestRunner // QT方式的TestRunner CppUnit::MfcUi::TestRunner // MFC方式的TestRunner
|
下面是一个TestRunner的例子:
CppUnit::TextUi::TestRunner runner; CppUnit::TestSuite *suite= new CppUnit::TestSuite(); // 添加一个测试用例 suite->addTest(new CppUnit::TestCaller<MathTest> ("testAdd", testAdd)); // 指定运行TestSuite runner.addTest( suite ); // 开始运行, 自动显示测试进度和测试结果 runner.run( "", true ); // Run all tests and wait
|
按照上面的方式,如果要添加新的测试用例,需要把每个测试用例添加到 TestSuite 中,而且添加新的 TestFixture 需要把所有头文件添加到 main.cpp 中,比较麻烦。为此 CppUnit 提供了 CppUnit::TestSuiteBuilder,CppUnit::TestFactoryRegistry 和一堆宏,用来方便地把 TestFixture 和测试用例注册到 TestSuite 中。下面就是通常的使用方式(注意红色字体)
/// MathTest.h
#include "cppunit/extensions/HelperMacros.h" class MathTest : public CppUnit::TestFixture { // 声明一个TestSuite CPPUNIT_TEST_SUITE( MathTest ); // 添加测试用例到TestSuite, 定义新的测试用例需要在这儿声明一下 CPPUNIT_TEST( testAdd ); // TestSuite声明完成 CPPUNIT_TEST_SUITE_END(); // 其余不变 protected: intm_value1, m_value2; public: MathTest() {} // 初始化函数 voidsetUp (); // 清理函数 voidtearDown(); // 测试加法的测试函数 voidtestAdd (); // 可以添加新的测试函数 };
|
/// MathTest.cpp
// 把这个TestSuite注册到名字为"alltest"的TestSuite中, 如果没有定义会自动定义 // 也可以CPPUNIT_TEST_SUITE_REGISTRATION( MathTest );注册到全局的一个未命名的TestSuite中. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( MathTest, "alltest" ); // 下面不变 void MathTest::setUp() { m_value1 = 2; m_value2 = 3; } void MathTest::tearDown(){ } void MathTest::testAdd(){ intresult = m_value1 + m_value2; CPPUNIT_ASSERT( result == 5 ); }
|
/// main.cpp
// 不用再包含所有TestFixture子类的头文件 #include <cppunit/extensions/TestFactoryRegistry.h> #include <cppunit/ui/text/TestRunner.h> // 如果不更改TestSuite, 本文件后期不需要更改. intmain() { CppUnit::TextUi::TestRunner runner; // 从注册的TestSuite中获取特定的TestSuite, 没有参数获取未命名的TestSuite. CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry("alltest"); //若没有注册名字,在MathTest.cpp文件中只是调用了CPPUNIT_TEST_SUITE_REGISTRATION( MathTest );那就可以写成 CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry(); // 添加这个TestSuite到TestRunner中 runner.addTest( registry.makeTest() ); // 运行测试 runner.run(); }
|
/// mainanother.cpp //另外的一种写法。其实和上面大同小异,只是生成的对象是Test而不是registry了。
intmain(intargc, char* argv[]) { // Get the top level suite from the registry CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); // Adds the test to the list of test to run CppUnit::TextUi::TestRunner runner; runner.addTest( suite ); // Change the default outputter to a compiler error format outputter runner.setOutputter( new CppUnit::CompilerOutputter( &runner.result(),std::cerr ) ); // Run the tests. boolwasSucessful = runner.run(); // Return error code 1 if the one of test failed. returnwasSucessful ? 0 : 1; }
|
这样添加新的测试用例(TestFixture)只需要在类定义的开始声明一下即可。
转载自:
http://wenku.baidu.com/view/dc31d1e69b89680203d825ac.html