您的位置:首页 > 编程语言 > C语言/C++

使用CppUnit编写测试程序

2005-08-24 14:23 441 查看
******************************************************************************
* 使用CppUnit编写测试程序的大致流程
* 20050823 by daineng@nj.cpsecure
******************************************************************************
****************************************************************************
* 需要先知道的:
* 除了头文件的路径,库文件(或许还用的上动态库),CodeGeneration还需要设置
* 成 Multi-threaded Debug Dll
****************************************************************************

* 最简单的一个例子
--------------------------------------------------------------------------
class MyTestCase : public CPPUNIT_NS::TestCase {
public:
virtual void runTest() {
CPPUNIT_ASSERT_EUQAL(1, 2);
}
};
然后
MyTestCase case;
case.runTest();
CPPUNIT_ASSERT_EQUAL是一个宏,在它的两个参数不相等的时候,会抛出异常。

* Windows Console
--------------------------------------------------------------------------
MyTestCase case;
CPPUNIT_NS::TestResult result;
CPPUNIT_NS:;TestResultCollector collector;
result.addListener(&collector);
case.run(&result);
CPPUNIT_NS::TextOutputter out(&collector, std::cout);
out.write();
# 似乎在这里不需要动态库文件
TestResult实际上是一个测试的控制器,在调用TestCase.run()时,需要提供一个
TestResult。run作为测试的进行方,会把测试中产生的信息发送给TestResult,
而TestResult作为一个分发器,会把所受到的消息再转发给Listener。也就是说,
如果简单定义一个TestResult并且把它的指针传给TestCase::run(),这个程序也
能够编译通过并正确运行,但是不会有任何输出。TestResultCollector可以把测
试输出的信息都收集起来,并且最后通过TextOutputter输出。
同样 CPPUNIT_ASSERT_EQUAL 在测试不相等时会抛出异常,但这里不会异常退出。
TestCase.run()使用特殊的机制把函数包起来,任何异常都会被捕获。

* More Test
--------------------------------------------------------------------------
以上只能测试一个实例(一个过程,在TestCase.runTest()中指定),如果要同时
测试多个过程的话,MyTestCase则需要从CPPUNIT_NS::TestFixture继承。为区别,
使用 class MyTestFixture : public CPPUNIT::TestFixture
TestCase : This class is used to implement a simple test case.
TestFixture : A TestFixture is used to provide a common environment for
a set of test case.
# 注意到,TestCase的一个父类就是 TestFixture。TestCase提供了一个可使用的
测试接口:run() 和 runTest()
class CPPUNIT_API TestCase : public TestLeaf,
public TestFixture
TestFixture提供了setUp()和tearDown()函数提供测试前的初始化和测试后的清理
工作。我们可以在MyTestFixture实现几个自己的测试函数(测试过程):
testFunction1();
testFunction2();
为run这些测试过程,需要以下的过程:
CPPUNIT_NS::Test *test1 = new CPPUNIT_NS::TestCaller<MyTestFixture>(
"testFunction1", &MyTestFixture::testFunction1);
CPPUNIT_NS::Test *test2 = new CPPUNIT_NS::TestCaller<MyTestFixture>(
"testFunction2", &MyTestFixture::testFunction2);
test1->run();
test2->run();

# 以上是CppUnit中TextFixture.h中的示例,实际上更直观的是不要使用
CPPUNIT_NS::Test对象,直接使用TestCaller对象,如下:
CPPUNIT_NS::TestCaller<MyTestFixture> testcaller1 (
"testFunction1", &MyTestFixture::testFunction1);
CPPUNIT_NS::TestCaller<MyTestFixture> testcaller2 (
"testFunction2", &MyTestFixture::testFunction2);
testcaller1.run(result);
testcaller2.run(result);
CPPUNIT_NS::TestCaller
A test caller provides access to a test case method on a test
fixture class. Test callers are useful when you want to run an
individual test or add it to a suite.
Test Callers invoke only one Test (i.e. test method) on one
Fixture of a TestFixture.
#
######
#
到目前为止,涉及到的情况仍是单一的测试过程,要测试一批过程,首先要将所有
的过程逐个添加到一个集合中去,下面先从父类到子类的顺序介绍这个集合。
class CPPUNIT_API Test
All test objects should be a subclass of Test. Some test objects,
TestCase for example, represent one individual test. Other test
objects, such as TestSuite, are comprised of several tests.
CPPUNIT_NS::Test提供了一个run()函数,剩下的部分实现的功能如同一个链表
的节点需要的那样。
class CPPUNIT_API TestComposite : public Test
Base class for all test composites. Subclass this class if you need
to implement a custom TestSuite.
class CPPUNIT_API TestSuite : public TestComposite
A Composite of Tests.
TestSuite既继承自TestComposite,也包含一个由Test构成的向量。可以看得出
它能够递归地构成一棵树。
往TestSuite中添加测试过程:
CPPUNIT_NS::TestSuite *suite = new CPPUNIT_NS::TestSuite;
suite->addTest( new CPPUNIT_NS::TestCaller<MyTestFixture>(
"testFunction1", testFunction1 ) );
suite->addTest( new CPPUNIT_NS::TestCaller<MyTestFixture>(
"testFunction2", testFunction2 ) );
上面的过程通常定义在MyTestCase或MyTestFixture中,并且返回这个suite,
返回的类型为CPPUNIT_NS::Test*
和第一次提到Test这个类一样,我们碰到了一个问题,Test和TestCaller似乎是两
个不相关的类,怎么能够将 TestCaller* 赋值给 Test*?
# void TestSuite::addTest( Test *test )
答案在于TestCaller的父类TestCase的一个父类是TestLeaf,而TestLeaf又继承于
Test。可以这样看,TestFixture, TestCase, TestCaller构成测试实体,而Test,
TestComposite, TestSuite构成测试节点/集合。
CppUnit提供了一组宏来方便做addTest()的工作:
CPPUNIT_TEST_SUITE(MyTestFixture);
CPPUNIT_TEST(testFunction1);
CPPUNIT_TEST(testFunction2);
CPPUNIT_TEST_END();
这组宏还实现了一个suite函数返回 TestSuite*
到目前为止我们得到了一个包含许多测试过程的集合suite,下面介绍怎么run这个
集合中的测试过程。
CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest->run(&result);
getRegistry(const std::string &name)是TestFactoryRegistry的静态函数,通
过一个名字返回一个TestFactoryRegistry的对象引用(有默认的名字),
makeTest()是TestFactoryRegistry的成员函数,返回Test的指针,用这个指针就
可以调用run()函数来进行测试了。
要使getRegistry得到MyTestFactory,一般要在MyTestFixture的源文件中使用:
CPPUNIT_TEST_SUITE_REGISTRATION( MyTestFixture );
这个宏实际上产生了一个静态全局的AutoRegisterSuite对象,细节不再讨论。
另外,使用CPPUNIT_TEST_SUITE_NAMED_REGISTRATION宏可以将MyTestFixture与
一个有名字的TestFactoryRegistry联系起来,要得到这个TestFactoryRegistry
对象引用的方式只需要在getRegistry()函数的参数中指定这个名字就可以了。

* MFC DIALOG UI
--------------------------------------------------------------------------
/*********************************************
* Header Needed:
* cppunit/ui/mfc/TestRunner.h
*********************************************/
CPPUNIT_NS::MfcUi::TestRunner runner;
runner.addTest(MY_TEST_NS::suite()); // 这个函数将runner和TEST-SUITE
// 联系起来
runner.run(); // 调用CppUnit的测试对话框
MY_TEST_NS::suite()代表测试的入口点,其实现如下:
/*********************************************
* Header Needed:
* cppunit/extensions/TestFactoryRegistry.h
* cppunit/TestSuite.h
*********************************************/
namespace MY_TEST_NS {
CPPUNIT_NS:Test* suite() {
CPPUNIT_NS::TestFactoryRegistry ®istry =
CPPUNIT_NS::TestFactoryRegistry::getRegistry(SuiteName());
return registry.makeTest();
}
} // 这里似乎没有用到TestSuite类
SuiteName是MY_TEST_NS域中的一个使用者实现的函数,简单返回一个const
std::string,这个字符串是测试入口点的名字。
有了Test-Suite之后,接下来要准备Test-Case:
/*********************************************
* Header Needed:
* cppunit/extensions/HelperMacro.h
* 这个头文件包含了<cppunit/TestCaller.h>和
* <cppunit/TestSuite.h>,其中前者包含了
* <cppunit/TestCase.h>
*********************************************/
class CMyTestCase : public CPPUNIT_NS::TestCase {
CPPUNIT_TEST_SUITE(CMyTestCase);
CPPUNIT_TEST(TEST_FUNC); // TEST_FUNC是CMyTestCase的成员函数
// 一个CASE下可以有多个函数,只需要
// 重复使用CPPUNIT_TEST宏
CPPUNIT_TEST_SUITE_END();
public:
void TEST_FUNC();
};
最后,将一个TEST-CASE加入一个TEST-SUITE:
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CMyTestCase,
MY_TEST_NS::SuiteName());
同样可以使用多次以将更多的TEST-CASE加入TEST_SUITE中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐