《实时控制软件设计》之单元测试
作者:网络转载 发布时间:[ 2015/12/28 11:31:11 ] 推荐标签:软件测试 单元测试
在主程序中创建MyTest的实例test1,并执行测试函数test1.runTest()。运行结果显示第二项测试没有通过。
上面是简单的单元测试代码,但实际的单元测试往往不是直接使用 TestCase类,而是用TestFixture类,TestFixture类拥有TestSuite,每个TestSuite又可以拥有多个TestCase。下面是第2个示例代码:
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/ui/text/TestRunner.h>
class MyTests : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE( MyTests );
CPPUNIT_TEST( testAdd );
CPPUNIT_TEST( testEquals );
CPPUNIT_TEST_SUITE_END();
double m_value1;
double m_value2;
public:
void setUp()
{
m_value1 = 2.0;
m_value2 = 3.0;
}
void tearDown()
{
}
void testAdd()
{
double result = m_value1 + m_value2;
CPPUNIT_ASSERT( result == 6.0 );
}
void testEquals()
{
long* l1 = new long(12);
long* l2 = new long(12);
CPPUNIT_ASSERT_EQUAL( 12, 12 );
CPPUNIT_ASSERT_EQUAL( 12L, 12L );
CPPUNIT_ASSERT_EQUAL( *l1, *l2 );
delete l1;
delete l2;
CPPUNIT_ASSERT( 12L == 12L );
CPPUNIT_ASSERT_EQUAL( 12, 13 );
CPPUNIT_ASSERT_DOUBLES_EQUAL( 12.0, 11.99, 0.5 );
}
};
int main()
{
CppUnit::TextUi::TestRunner runner;
runner.addTest( MyTests::suite() );
runner.run();
return 0;
}
分析下这个程序,我们发现在类MyTests的定义中采用了如下宏:
CPPUNIT_TEST_SUITE( MyTests );
CPPUNIT_TEST( testAdd );
CPPUNIT_TEST( testEquals );
CPPUNIT_TEST_SUITE_END();
其作用是定义了两个TestCase: testAdd和testEquals,并把这两个TestCase添加到一个叫MyTests的TestSuite中去。
在主程序中实例化了一个TestRunner类对象runner,把MyTests这个测试用例集合添加到runner,然后调用runner.run()自动执行所有的测试用例了。
从这个程序中,我们也可以体会到面向对象编程的一些思想方法。每次具体的单元测试的内容都是变化的,但是单元测试的基本原理和流程是不变的,我们的程序设计应该把不变的部分和变化的部分有效地区隔开来。在上面程序中,TestRunner对象相当于工厂里的质检员,他只按照标准的测试流程工作,所以我们不需要重新定义它,而是直接用CPPUNIT的类定义实例化一个对象,但TestRunner具体执行什么测试取决于我们提供给它什么测试用例集,所以我们只需要定义一个具体的测试用例集,并把该测试用例集传递给TestRunner,TestRunner通过调用它的标准作业流程run(),去执行每一个测试用例并返回结果。所以我们看主函数中的三行代码:
CppUnit::TextUi::TestRunner runner;
runner.addTest( MyTests::suite() );
runner.run();
第1行和第3行都不需要随着测试用例集的变化而变化,只有在第2行中,要把自定义的测试用例集名传递给TestRunner。
为了实现自动化的单元测试,我们希望当开发人员编写新的模块并增加或修改单元测试程序时,测试框架程序不随之变化。我们来看看KDL库里是如何实现这一点的。
framestest.hpp和framestest.cpp是一个具体的单元测试代码,里面具体的测试用例用来测试KDL的frames模块,如下面的一个测试宏:
CPPUNIT_ASSERT_DOUBLES_EQUAL((R*v).Norm(),v.Norm(),epsilon);
是为了测试一个向量v进行旋转操作R后是否保持模不变,从数学上讲模是完全不变的,但数值运算上肯定有精度问题,这里用epsilon来测试运算精度是否在epsilon范围内。
整个代码结构和上面第2个例程基本类似,稍有不同的是在framestest.cpp的开始部分,有一行代码
CPPUNIT_TEST_SUITE_REGISTRATION( FramesTest );
在KDL的tests目录中,有多个与FramesTest类似的单元测试代码,其结构和风格都类似,如JacobianTest,在其cpp实现文件中也有一行代码:
CPPUNIT_TEST_SUITE_REGISTRATION(JacobianTest);
test-runner.cpp则给出了测试框架程序:
#include <cppunit/XmlOutputter.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
#include <iostream>
#include <fstream>
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 );
#ifndef TESTNAME
std::ofstream outputFile(std::string(suite->getName()+"-result.xml").c_str());
#else
std::ofstream outputFile((std::string(TESTNAME)+std::string("-result.xml")).c_str());
#endif
// Change the default outputter to a compiler error format outputter
runner.setOutputter( new CppUnit::XmlOutputter( &runner.result(),outputFile ) );
// Run the tests.
bool wasSucessful = runner.run();
outputFile.close();
// Return error code 1 if the one of test failed.
return wasSucessful ? 0 : 1;
}
主函数中有几行代码用于创建了一个log文件用于记录单元测试的结果,有两行代码
runner.addTest( suite );
bool wasSucessful = runner.run();
和第2个例子是完全相同的,不同的是在第2个例子中,我们需要直接把具体TestSuite名添加到runner中,但在这个框架程序中,使用了一行代码自动收集KDL所有的单元测试用例添加到suite中:
CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest();
这个是设计模式中的工厂方法模式,每个具体的单元测试类通过CPPUNIT_TEST_SUITE_REGISTRATION宏把自己注册到工厂类中去,然后框架程序通过工厂类的方法自动创建所有的测试用例集对象,在项目开发过程中,test-runner.cpp作为测试框架程序不需要随着单元测试数量的变化进行代码的修改,可以自动执行并生成测试结果报告,这里也充分体现了设计模式的威力。
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
iOS单元测试mocha、chai、sinon和istanbul实现百分之百的单元测试覆盖率关于单元测试的总结及思考编写更好的Java单元测试的7个技巧Android单元测试框架Robolectric3.0介绍(一)使用Kiwi单元测试总结单元测试如此重要,为什么你不知道Python单元测试??使用装饰器实现测试跳过和预期故障对Controller的单元测试写好单元测试的10个技巧单元测试的重要性Angular单元测试系列??Component、Directive、Pipe 以及ServiceAndroid单元测试的整理提升单元测试体验的利器--Mockito使用总结iOS UnitTest单元测试Vue的单元测试探索(二)
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南