校园网站建设促进教学,h5网站的优势,网站导航下拉菜单代码,毕业设计网站做几个简介 测试是软件开发过程中极其重要的一环#xff0c;详尽周密的测试能够减少软件BUG#xff0c;提高软件品质。测试包括单元测试、系统测试等。其中单元测试是指针对软件功能单元所作的测试#xff0c;这里的功能单元可以是一个类的属性或者方法#xff0c;测试的目的是看… 简介 测试是软件开发过程中极其重要的一环详尽周密的测试能够减少软件BUG提高软件品质。测试包括单元测试、系统测试等。其中单元测试是指针对软件功能单元所作的测试这里的功能单元可以是一个类的属性或者方法测试的目的是看这些基本单元是否工作正常。由于单元测试的内容很基础因此可以看作是测试工作的第一环该项工作一般由开发人员自行完成。如果条件允许单元测试代码的开发应与程序代码的开发同步进行。 虽然不同程序的单元测试代码不尽相同但测试代码的框架却非常相似于是便出现了一些单元测试类库CppUnit便是其中之一。 CppUnit是XUnit中的一员XUnit是一个大家族还包括JUnit和PythonUnit等。CppUnit简单实用学习和使用起来都很方便网上已有一些文章对其作介绍但本文更着重于讲解其中的基本概念和使用方法以帮助初次接触CppUnit的人员快速入门。 安装 1、 先下个最新版cppunit-1.12.1.tar.gz 解压缩进入cppunit-1.12.1\src目录就是源代码所在打开CppUnitLibraries.dsw工程是用vc6.0写的用vs2010转换到CppUnitLibraries.sln ok
2、 然后依次运行CppUnitLibraries.dsw工程下的每个项目这样做的目的是为了方面发现问题和找到正确的解决方法。下面是我在运行相应项目时所提示的错误以及解决办法。未贴图把下述的解决办法都做完即可不需要查看贴图的错误提示
1) 运行项目Cppunit
解决办法
选择Cppunit右键属性 -debug配置属性-常规-目标文件名$(ProjectName)修改成cppunitd这样做是为保持链接器-常规-目标文件名 一致 2) 运行项目cppunit_dll 解决办法 选择Cppunit右键属性-debug配置属性-常规-目标文件名$(ProjectName)修改成cppunitd_dll这样做是为保持库管理器-常规-目标文件名 一致
3到这里这里会发现其实每个项目的错误基本上都是TargeName(xxx)与Linker的OutputFile属性值不匹配依次修改项目DllPlugInTester、DSPlugIn、TestPlugInRunner、TestRunner的Debug配置属性每个后面都记得加个”d”而且库管理器中为目标文件名.xxxx不需要修改但库管理器中的目标文件名可能要修改该成与常规—目标文件名一致
4当然当修改完DSPlugIn的Debug配置属性后再运行我们发现 我们仔细观察到底新的错误是什么呢 这里修改方式就是最上面的红色字中提到的
修改TestRunner下UserInterface\DynamicWindow\MsDevCallerListCtrl.cpp文件第67行改成#importlibid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2 version(8.0)lcid(0) raw_interfaces_only named_guids
5再次运行DSPlugIn项目我们会发现依然有错误 解决方法
选择项目-属性-配置属性-链接器-高级-无入口点 选择是(/NOENTRY)
6)最后为了生成全面的库文件我需要分别在Debug、release、Debug unicode、release unicode四种配置属性中生成全部解决方案。运行过程中会遇到错误基本上都可以从上文中找到解决方法
7)编译完成后提示成功6 失败 0 即安装完毕
**************************************************************************************************详细说明 解压后你可以看到CppUnit包含如下目录 config 配置文件contrib contribution其他人贡献的外围代码doc 文档需要通过doxygen工具生成也可以直接从sourceforge站点上下载打包好的文档examples示例代码include 头文件lib 存放编译好的库src 源文件以及编译库的工程等 然后打开src目录下的CppUnitLibraries工程执行build/batch build编译成功的话生成的库文件将被拷贝到lib目录下。 你也可以根据需要选择所需的项目进行编译其中项目cppunit为静态库cppunit_dll为动态库生成的库文件为 cppunit.lib 静态库release版cppunitd.lib 静态库debug版cppunit_dll.lib 动态库release版cppunitd_dll.lib动态库debug版 要使用CppUnit还得设置好头文件和库文件路径以VC6为例选择Tools/Options/Directories在Include files和Library files中分别添加%CppUnitPath%/include和%CppUnitPath%/lib其中%CppUnitPath%表示CppUnit所在路径。 做好准备工作后我们就可以编写自己的单元测试代码了。需说明的是CppUnit所用的动态运行期库均为多线程动态库因此你的单元测试程序也得使用相应设置否则会发生冲突。 概念 在使用之前我们有必要认识一下CppUnit中的主要类当然你也可以先看后面的例子遇到问题再回过头来看这一节。 CppUnit核心内容主要包括六个方面 1. 测试对象TestTestFixture...用于开发测试用例以及对测试用例进行组织管理。 2. 测试结果TestResult 处理测试用例执行结果。TestResult与下面的TestListener采用的是观察者模式Observer Pattern。 3. 测试结果监听者TestListener TestListener作为TestResult的观察者担任实际的结果处理角色。 4. 结果输出Outputter 将结果进行输出可以制定不同的输出格式。 5. 对象工厂TestFactory 用于创建测试对象对测试用例进行自动化管理。 6. 测试执行体TestRunner 用于运行一个测试。 以上各模块的主要类继承结构如下 Test TestFixture TestResult TestListener _______|_________ | | | | | TestSuccessListenerTestComposite TestLeaf | | | |____________| TestResultCollector TestSuit |TestCase |TestCallerFixtureOutputter TestFactory TestRunner____________________|_________________ || | | TestFactoryRegistryCompilerOutputter TextOutputter XmlOutputter |TestSuiteFactoryTestCaseType接下来再对其中一些关键类作以介绍。 Test所有测试对象的基类。 CppUnit采用树形结构来组织管理测试对象类似于目录树因此这里采用了组合设计模式Composite PatternTest的两个直接子类TestLeaf和TestComposite分别表示“测试树”中的叶节点和非叶节点其中TestComposite主要起组织管理的作用就像目录树中的文件夹而TestLeaf才是最终具有执行能力的测试对象就像目录树中的文件。 Test最重要的一个公共接口为
virtual void run(TestResult *result) 0;其作用为执行测试对象将结果提交给result。 在实际应用中我们一般不会直接使用Test、TestComposite以及TestLeaf除非我们要重新定制某些机制。 TestFixture用于维护一组测试用例的上下文环境。 在实际应用中我们经常会开发一组测试用例来对某个类的接口加以测试而这些测试用例很可能具有相同的初始化和清理代码。为此CppUnit引入TestFixture来实现这一机制。 TestFixture具有以下两个接口分别用于处理测试环境的初始化与清理工作
virtual void setUp(); //初始化 virtual void tearDown(); //清理 TestCase测试用例从名字上就可以看出来它便是单元测试的执行对象。 TestCase从Test和TestFixture多继承而来通过把Test::run制定成模板函数Template Method而将两个父类的操作融合在一起run函数的伪定义如下
// 伪代码 void TestCase::run(TestResult* result) { result-startTest(this); // 通知result测试开始 if( result-protect(this, TestCase::setUp) ) // 调用setUp初始化环境 result-protect(this, TestCase::runTest); // 执行runTest即真正的测试代码 result-protect(this, TestCase::tearDown); // 调用tearDown清理环境 result-endTest(this); // 通知result测试结束 }这里要提到的是函数runTest它是TestCase定义的一个接口原型如下
virtual void runTest();用户需从TestCase派生出子类并实现runTest以开发自己所需的测试用例。 另外还要提到的就是TestResult的protect方法其作用是对执行函数实际上是函数对象的错误信息包括断言和异常等进行捕获从而实现对测试结果的统计。 TestSuit测试包按照树形结构管理测试用例 TestSuit是TestComposite的一个实现它采用vector来管理子测试对象Test从而形成递归的树形结构。 TestCallerTestCase适配器Adapter它将成员函数转换成测试用例 虽然我们可以从TestCase派生自己的测试类但从TestCase类的定义可以看出它只能支持一个测试用例这对于测试代码的组织和维护很不方便尤其是那些有共同上下文环境的一组测试。为此CppUnit提供了TestCaller以解决这个问题。 TestCaller是一个模板类它以实现了TestFixture接口的类为模板参数将目标类中某个符合runTest原型的测试方法适配成TestCase的子类。 在实际应用中我们大多采用TestFixture和TestCaller相组合的方式具体例子参见后文。 TestResult和TestListener处理测试信息和结果 前面已经提到TestResult和TestListener采用了观察者模式TestResult维护一个注册表用于管理向其登记过的TestListener当TestResult收到测试对象Test的测试信息时再一一分发给它所管辖的TestListener。这一设计有助于实现对同一测试的多种处理方式。 TestFactory测试工厂 这是一个辅助类通过借助一系列宏定义让测试用例的组织管理变得自动化。参见后面的例子。 TestRunner用于执行测试用例 TestRunner将待执行的测试对象管理起来然后供用户调用。其接口为
virtual void addTest( Test *test ); virtual void run( TestResult controller, const std::string testPath );这也是一个辅助类需注意的是通过addTest添加到TestRunner中的测试对象必须是通过new动态创建的用户不能删除这个对象因为TestRunner将自行管理测试对象的生命期。 CppUnit在vs2010中配置 参考Vs2010下使用CppUint初体验 http://blog.csdn.net/leer168/article/details/6708732 vs2010代码实例 CppUnitTest1 先让我们看看一个简单的例子 #include cppunit/TestCase.h #include cppunit/TestResult.h #include cppunit/TestResultCollector.h #include cppunit/TextOutputter.h // 定义测试用例 class SimpleTest : public CppUnit::TestCase { public: void runTest() // 重载测试方法 { int i 1; CPPUNIT_ASSERT_EQUAL(0, i); } }; int main(int argc, char* argv[]) { CppUnit::TestResult r; CppUnit::TestResultCollector rc; r.addListener(rc); // 准备好结果收集器 SimpleTest t; t.run(r); // 运行测试用例 CppUnit::TextOutputter o(rc, std::cout); o.write(); // 将结果输出 return 0; } 编译后运行输出结果为 !!!FAILURES!!! Test Results: Run: 1 Failures: 1 Errors: 0 1) test: (F) line: 18 E:/CppUnitExamples/SimpleTest.cpp equality assertion failed - Expected: 1 - Actual : 0 上面的例子很简单需说明的是CPPUNIT_ASSERT_EQUAL宏。CppUnit定义了一组宏用于检测错误CPPUNIT_ASSERT_EQUAL是其中之一当断言失败时CppUnit便会将错误信息报告给TestResult。这些宏定义的说明如下 CPPUNIT_ASSERT(condition)判断condition的值是否为真如果为假则生成错误信息。 CPPUNIT_ASSERT_MESSAGE(message, condition)与CPPUNIT_ASSERT类似但结果为假时报告messsage信息。 CPPUNIT_FAIL(message)直接报告messsage错误信息。 CPPUNIT_ASSERT_EQUAL(expected, actual)判断expected和actual的值是否相等如果不等输出错误信息。 CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual)与CPPUNIT_ASSERT_EQUAL类似但断言失败时输出message信息。 CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta)判断expected与actual的偏差是否小于delta用于浮点数比较。 CPPUNIT_ASSERT_THROW(expression, ExceptionType)判断执行表达式expression后是否抛出ExceptionType异常。 CPPUNIT_ASSERT_NO_THROW(expression)断言执行表达式expression后无异常抛出。 CppUnitTest2 接下来再看看TestFixture和TestCaller的组合使用 #include cppunit/TestCase.h #include cppunit/TestResult.h #include cppunit/TestResultCollector.h #include cppunit/TextOutputter.h #include cppunit/TestCaller.h #include cppunit/TestRunner.h // 定义测试类 class StringTest : public CppUnit::TestFixture { public: void setUp() // 初始化 { m_str1 Hello, world; m_str2 Hi, cppunit; } void tearDown() // 清理 { } void testSwap() // 测试方法1 { std::string str1 m_str1; std::string str2 m_str2; m_str1.swap(m_str2); CPPUNIT_ASSERT(m_str1 str2); CPPUNIT_ASSERT(m_str2 str1); } void testFind() // 测试方法2 { int pos1 m_str1.find(,); int pos2 m_str2.rfind(,); CPPUNIT_ASSERT_EQUAL(5, pos1); CPPUNIT_ASSERT_EQUAL(2, pos2); } protected: std::string m_str1; std::string m_str2; }; int main(int argc, char* argv[]) { CppUnit::TestResult r; CppUnit::TestResultCollector rc; r.addListener(rc); // 准备好结果收集器 CppUnit::TestRunner runner; // 定义执行实体 runner.addTest(new CppUnit::TestCallerStringTest(testSwap, StringTest::testSwap)); // 构建测试用例1 runner.addTest(new CppUnit::TestCallerStringTest(testFind, StringTest::testFind)); // 构建测试用例2 runner.run(r); // 运行测试 CppUnit::TextOutputter o(rc, std::cout); o.write(); // 将结果输出 return rc.wasSuccessful() ? 0 : -1; } 编译后运行结果为
OK (2 tests)CppUnitTest3 上面的代码从功能上讲没有什么问题但编写起来太繁琐了为此我们可以借助CppUnit定义的一套辅助宏将测试用例的定义和注册变得自动化。上面的代码改造后如下 #include cppunit/TestResult.h #include cppunit/TestResultCollector.h #include cppunit/TextOutputter.h #include cppunit/TestRunner.h #include cppunit/extensions/HelperMacros.h // 定义测试类 class StringTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(StringTest); // 定义测试包 CPPUNIT_TEST(testSwap); // 添加测试用例1 CPPUNIT_TEST(testFind); // 添加测试用例2 CPPUNIT_TEST_SUITE_END(); // 结束测试包定义 public: void setUp() // 初始化 { m_str1 Hello, world; m_str2 Hi, cppunit; } void tearDown() // 清理 { } void testSwap() // 测试方法1 { std::string str1 m_str1; std::string str2 m_str2; m_str1.swap(m_str2); CPPUNIT_ASSERT(m_str1 str2); CPPUNIT_ASSERT(m_str2 str1); } void testFind() // 测试方法2 { int pos1 m_str1.find(,); int pos2 m_str2.rfind(,); CPPUNIT_ASSERT_EQUAL(5, pos1); CPPUNIT_ASSERT_EQUAL(2, pos2); } protected: std::string m_str1; std::string m_str2; }; CPPUNIT_TEST_SUITE_REGISTRATION(StringTest); // 自动注册测试包 int main(int argc, char* argv[]) { CppUnit::TestResult r; CppUnit::TestResultCollector rc; r.addListener(rc); // 准备好结果收集器 CppUnit::TestRunner runner; // 定义执行实体 runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); runner.run(r); // 运行测试 CppUnit::TextOutputter o(rc, std::cout); o.write(); // 将结果输出 return rc.wasSuccessful() ? 0 : -1; }CppUnit的简单介绍就到此相信你已经了解了其中的基本概念也能够开发单元测试代码了。 其它CppUnit还包括其它一些辅助模块比如基于MFC的图形化测试界面下面这篇文章对此有所介绍 CppUnit测试框架入门CppUnit使用了很多设计模式整体构架还算清晰合理源码也比较简单易懂这对于学习设计模式是一个不错的选择。网上已有这样的一些资料 CppUnit源码解读CppUnit代码简介 - 第一部分核心类freefalcon于2006-05-22