分享
 
 
 

CppUnit使用指南

王朝other·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

CppUnit使用指南测试驱动开发的原则:Ø 先写测试代码,然后编写符合测试的代码。至少做到完成部分代码后,完成对应的测试代码;

Ø 测试代码不需要覆盖所有的细节,但应该对所有主要的功能和可能出错的地方有相应的测试用例;

Ø 发现 bug,首先编写对应的测试用例,然后进行调试;

Ø 不断总结出现 bug 的原因,对其他代码编写相应测试用例;

Ø 每次编写完成代码,运行所有以前的测试用例,验证对以前代码影响,把这种影响尽早消除;

Ø 不断维护测试代码,保证代码变动后通过所有测试;

Ø 在编码前:他可以强迫你对需求进行详细的分析。

Ø 在编码时:他可以使你对over coding保持警觉。

Ø 在重构时:可以确保新的设计能够兼容旧版本的功能。

Ø 在团队开发时:可以确保自己的单元是无误的。

CppUnit的原理在 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必须注意以下几点:

Ø 可以自动执行,不用人手操作。

Ø 自动返回测试结果。

Ø 绝对的独立,不能与其他TestCase有任何联系。就算测试同一个函数的不同功能也需要分开。每个TestCase可以说是一个孤岛。

对 fixture 的所有测试用例可以被封装在一个 CppUnit::TestFixture 的子类(命名惯例是[ClassName]Test)中。然后定义这个fixture 的 setUp 和 tearDown 函数,为每个测试用例定义一个测试函数(命名惯例是 testXXX)。下面是个简单的例子:

class MathTest : public CppUnit::TestFixture {

protected:

int m_value1, m_value2;

public:

MathTest() {}

// 初始化函数

void setUp () {

m_value1 = 2;

m_value2 = 3;

}

// 测试加法的测试函数

void testAdd () {

// 步骤(2),对 fixture 进行操作

int result = 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:

int m_value1, m_value2;

public:

MathTest() {}

// 初始化函数

void setUp ();

// 清理函数

void tearDown();

// 测试加法的测试函数

void testAdd ();

// 可以添加新的测试函数

};

/// 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(){

int result = m_value1 + m_value2;

CPPUNIT_ASSERT( result == 5 );

}

/// main.cpp// 不用再包含所有TestFixture子类的头文件

#include <cppunit/extensions/TestFactoryRegistry.h>

#include <cppunit/ui/text/TestRunner.h>

// 如果不更改TestSuite, 本文件后期不需要更改.

int main()

{

CppUnit::TextUi::TestRunner runner;

// 从注册的TestSuite中获取特定的TestSuite, 没有参数获取未命名的TestSuite.

CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry("alltest");

//若没有注册名字,在MathTest.cpp文件中只是调用了CPPUNIT_TEST_SUITE_REGISTRATION( MathTest );那就可以写成

CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry();

// 添加这个TestSuite到TestRunner中

runner.addTest( registry.makeTest() );

// 运行测试

runner.run();

}

/// mainanother.cpp另外的一种写法。其实和上面大同小异,只是生成的对象是Test而不是registry了。

int main(int argc, 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.

bool wasSucessful = runner.run();

// Return error code 1 if the one of test failed.

return wasSucessful ? 0 : 1;

}

这样添加新的测试用例(TestFixture)只需要在类定义的开始声明一下即可。

其他实际问题通常包含测试用例代码和被测试对象是在不同的项目中。应该在另一个项目(最好在不同的目录)中编写 TestFixture,然后把被测试的对象包含在测试项目中。

对某个类或者某个函数进行测试的时候,这个 TestFixture 可能引用了别的类或者别的函数,为了隔离其他部分代码的影响,应该在源文件中临时定义一些桩程序,模拟这些类或者函数。这些代码可以通过宏定义在测试项目中有效,而在被测试的项目中无效。

CppUnit的组成结构

2 核心部分(Core)

2.1 基本测试类

2.1.1 Test

2.1.2 TestFixture

2.1.3 TestCase

2.1.4 TestSuite

2.2 测试结果记录

2.2.1 SynchronizedObject

2.2.2 TestListener

2.2.3 TestResult

2.3 错误处理

2.3.1 TestFailure

2.3.2 SourceLine

2.3.3 Exception

2.3.4 NotEqualException

2.4 断言

2.4.1 Asserter

2.4.2 TestAssert

3 输出部分(Output)

3.1 基础部件

3.1.1 Outputter

3.1.2 TestResultCollector

3.2 衍生类

3.2.1 TextOutputter

3.2.2 CompilerOutputter

3.2.3 XmlOutputter

4 辅助部分(Helper)

4.1 创建机制

4.1.1 TypeInfoHelper

4.1.2 TestFactory

4.1.3 TestFactoryRegistry,NamedRegistries

4.1.4 TestSuiteFactory

4.1.5 TestSuiteBuilder

4.1.6 TestCaller

4.1.7 AutoRegisterSuite

4.2 HelperMacros

5 扩展部分(Extension)

5.1 TestDecorator

5.2 RepeatedTest

5.3 Orthodox

5.4 TestSetUp

6 兼听者部分(Listener)

6.1 TestSucessListener

6.2 TextTestProgressListener

6.3 TextTestResult

7 界面部分(TextUI)

7.1 TestRunner

8 移植(Portability)

8.1 OStringStream

8.2 其他

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有