单元测试之道Word格式文档下载.docx
- 文档编号:411288
- 上传时间:2023-04-28
- 格式:DOCX
- 页数:13
- 大小:375.43KB
单元测试之道Word格式文档下载.docx
《单元测试之道Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《单元测试之道Word格式文档下载.docx(13页珍藏版)》请在冰点文库上搜索。
4[Test]
5publicvoidTestAddAndRemoveRole()
6{
7IRoleServicesroleServ=UnityHelper.CreateContainer().Resolve<
IRoleServices>
();
8IRoleRepositoryroleRep=UnityHelper.CreateContainer().Resolve<
IRoleRepository>
9Assert.IsNotNull(roleServ);
10Assert.IsNotNull(roleRep);
11
12StringtimeStamp=DateTime.Now.ToString();
13RoleDtonewRole=newRoleDto()
14{
15Name="
测试角色"
+timeStamp,
16Desciption="
此角色仅供测试使用"
17};
18roleServ.AddRole(newRole);
19
20RoleDtoaddedRole=roleRep.GetRoleByName("
+timeStamp);
21Assert.AreNotEqual(-1,addedRole.ID);
//确认新角色添加成功
22
23roleServ.RemoveRole(addedRole.ID);
24Assert.AreEqual(-1,roleRep.GetRoleByName("
+timeStamp).ID);
//确认刚才添加的角色删除成功
25}
上面的UnitTestCase来自我目前负责的一个项目,这段代码的作用是测试Services层对角色的添加和删除是否正常工作。
这里大家可以先不必太细究代码,后面会有详解。
为什么大家不使用单元测试
按照惯例,说完什么是单元测试,就该说为什么要使用单元测试了。
但是,我在这里想先和大家讨论,为什么很多开发人员知道单元测试,也“认为”单元测试有必要,但绝大多数开发人员都不写单元测试,能认真对待单元测试的开发人员更是寥寥无几了。
我私下调查了一些开发人员,发现大家不写单元测试主要有两点原因:
一是对单元测试存在很多误解,二是没有真正意识到单元测试的收益。
下面我就这两点做一些讨论。
首先,我们来看看大家对单元测试普遍存在哪些误解。
误解1:
单元测试属于测试工作,应该由测试人员来完成,所以单元测试不属于开发人员的职责范围。
正解1:
单元测试虽然叫做“测试”,但实际属于开发范畴,应该由开发人员来做。
在大多数开发人员眼里,“开发”和“测试”是两个泾渭分明的范畴,他们认为:
开发人员的工作就是写新代码,实现新功能,至于代码的测试,那是测试人员的职责,我只要让代码编译通过就行了。
我们都知道,软件是很复杂很抽象的东西,软件开发人员压力都很大,况且人非圣贤,强求开发人员开发出没有缺陷的程序是不现实的,所以才有了“测试工程师”这一职位。
但是,开发人员至少应该保证一点:
你写的每一个函数或方法(Function)应该能够正常完成功能,即行为正常。
软件最终可能会有缺陷,这不是开发人员完全可以控制的,但你写了一个类,类里有4个方法,作为开发人员应该保证这四个方法实现了“眼下”的功能。
例如,你写了一个获取IoC容器的工具类,你总要保证其中的GetContainer方法能正确返回一个Container吧。
所以,单元测试虽然叫“测试”,但实际其属于开发范畴,其目的是保证开发的功能子项能完成正确实现其基本功能。
甚至我个人认为,当开发人员开发每一个功能子项(通常是方法)时,如果不能附带一配套的单元测试代码,都不能算开发完成。
换言之,单元测试代码应该是开发人员必须提供的要素。
误解2:
单元测试是一种测试,其功能是对代码进行检测。
正解2:
单元测试是一种工具,其功能除了是对代码进行检测,更重要的是对软件的质量起到一种保证,并且是为他人和后续编码、重构工作提供的一种十分美妙的工具!
单元测试不是一种测试。
没错,我不是在说疯话,单元测试其实是一种工具。
特别是当自动化测试软件(如NUnit、JUnit)出现后,单元测试更像是一种工具了。
当你处在一个多人开发团队中,你需要和其他队友配合开发,而这在程序层面则表现为你开发的Class会被别人用,而你也会用别人开发的Class。
我们每个人都希望别人交给我的Class是行为正确的,如果我拿到一个同事写的数据库操作类DBHelper,但发现其中的Connect方法根本无法连接上数据库(虽然没有编译错误),那我将非常郁闷。
所以,在交给别人一个Class之前,你应该使用UnitTest保证这个Class是正常实现功能的,在交付的时候,你应该一手递上刚出炉的Class,然后另一只手递上配套的UnitTest,然后说:
嘿!
哥们,这是你要的类,而这个是配套的单元测试,你可以随时使用自动化测试工具运行它以便迅速知道这个类是否工作正常。
这将会是个很棒的工具,你的队友以后可能会想知道它的改动是否影响了你提供的类的功能,也可能会对你的类进行重构,但无论何时,它只要拿出你的配套单元测试,让自动化测试工具跑一下,不出几秒,就知道你提供的类是否还正常完成功能。
即使是对于你自己,以后也会有很多机会用到它。
而当你写的代码出现bug,你可以拿出你这段代码调用的所有类的单元测试跑一遍,很快就能知道到底是你依赖的类出了问题还是你自己代码有问题,而不必抓狂似地到处设断点。
误解3:
项目经理或技术主管没有要求写单元测试,所以不用写。
正解3:
写单元测试应该成为开发人员的一种本能,开发本身就应该包含些单元测试。
就像项目经理不用告诉你要使用计算机写程序一样,写单元测试应该成为开发人员的必须动作。
因为你是开发人员,因为你在做开发,所以你必须写单元测试,就这么简单。
误解4:
写单元测试获益者是测试人员,而开发人员无法从中获益,还要搭上宝贵的时间。
正解4:
写单元测试谁都获得不了像开发人员获得的那么大的益处。
有了单元测试,你可以随时从同事手中接过值得信赖的代码;
有了单元测试,你可以随时保证你写的代码行为正确;
有了单元测试,你可以随时通过自动化操作得知某个Class行为是否正确;
有了单元测试,你以后的Debug和重构工作将变得轻松异常;
有了单元测试,……没有人比开发人员从中获得的利益更大了。
为什么开发人员很难意识到单元测试的收益
关于这点,我认为有两个重要原因。
第一、绝大多数开发人员没有尝试过贯彻单元测试。
这个很好理解,如果你不亲口尝尝一道菜,即使是海参鲍鱼,你也不知道它有多美味。
我曾经也是其中的一员,但当我第一次将单元测试贯彻于项目中并尝到甜头后,我就爱上“她”了,所以,迈出一地步,很关键。
第二、人有一种天性:
相比长远的更大利益,人们更倾向于眼前的小的多的利益,正所谓“贪小便宜吃大亏”是也。
想起了美国人类行为专家的一个实验:
他到了美国一个小学,里面一个一年级班级有48个孩子,他给每个孩子5颗做了特殊标记的糖,并告诉他们如果到一周后谁能一颗都不吃,我就给他100颗糖。
一周后,48个孩子中只有4个孩子做到了。
他跟踪了这48个孩子30年的成长,最后发现那4个孩子都成为了十分成功的人物,他们4个人30年后拥有的财富是剩下44个孩子财富总和的3倍。
同样道理,即使很多开发人员也知道好的单元测试能让以后省不少心,但他们也宁可省掉写单元测试时间去堆砌代码。
因为我们总觉得今天省掉1个小时多写一个类更有的赚,虽然我们以后要为省掉的1小时多付出3个小时去抓狂。
小结一下
上面写了很多,所以我认为这里有必要小结一下,整理一下思绪。
单元测试的概念——一小段代码,用于检查一个或几个相关的方法行为是否正确。
单元测试的本质——随功能代码一起提供的一个配套工具。
单元测试的用途——保证交付Class行为正确,随时可用于自动化检测其对应的Class行为是否正确,对整个软件的质量是一种保证,对缺陷是一种控制。
为什么需要单元测试
我忽然发现,写了上面的文字后,再来讨论这个问题有些多余了,那么我尽量写简短一点。
1、开发人员有义务提供行为正确的Class,也有权利得到行为正确的Class。
很明显,如果你和你的同事,都能重视单元测试的话,你将同时履行这份义务和享受这份权利。
2、尽早消灭缺陷。
缺陷越早消灭所付出的代价越小,而越往后其代价呈指数增长,这是有充分的实验数据证明的,并已经被写到每一本软件工程教科书中。
毫无疑问,当你交付一个Class前,就将其行为上的缺陷全部扼杀,那将取得巨大的收益。
3、使合作变得愉快顺畅。
想想看,每个你调用的Class,都是经过你的同事测试,确保行为是正确的,这是多么美妙的事情!
我们写程序经常没有安全感,我们战战兢兢,很大程度上是因为我们没信心认为调用的每个Class行为是正确的。
4、得到一个有力的工具,会在后续工作中大显身手的工具。
如果每个Class都有配套的单元测试,好的,如果你想确认你的改动有没有影响到其它几个Class,runit!
如果你想看看你调用的类是否行为正确,runit!
如果你在重构,想看看重构有没有改变或损害其行为,runit!
你正在调试一个bug但很难定位问题出在哪个地方,runit!
你想看看目前项目中所有集成进来的代码是否行为都正确runit!
……
.NET平台下使用NUnit进行单元测试的实例
如果你愿意,你可以手工设计和运行单元测试,但这是低效和让人恐惧的。
目前,各个平台上都有较为流行的自动化单元测试工具,像VisualStudio2008本身就集成了单元测试功能。
但是,我更愿和大家分享的是一个叫NUnit的工具。
其官方网站为:
http:
//www.nunit.org/。
这是一个开源且免费的.NET平台下自动化单元测试工具,可以在其官网下载。
NUnit是XUnit家族的一员,其体积小巧,使用简单,但功能强大,一直是我做单元测试的首选。
另外,这个例子我选取目前我正负责的一个实际项目,这是一个国家863项目。
这个项目使用了敏捷开发方法,贯彻了以保证为目的的测试驱动、持续集成等实践。
我将截取其中几个片段和大家分享一下单元测试的一些实践。
值得一提的是,我对这个项目的单元测试要求是相对严格的,我们使用的配置管理工具是SVN,作为项目负责人,我对所有开发人员有一个要求:
每一个新开发的Class,必须有配套的单元测试,并且在每次Commit到SVN前,不仅仅要保证Commit的代码编译没问题,还要跑通所有单元测试,否则不准Commit到SVN。
这就保证了每个人Update到的Class都是行为正确的。
再配合面向接口编程方法和Mock技术,大大提高了代码的可测试性,使得开发过程一直比较让人满意。
刚开始大家觉得我的要求有些过分,但是当每次结合时几乎都没有出现问题,每次刚刚集成的新功能都能顺利在UI上跑通,大家也就慢慢接受了,并且渐渐都对待单元测试非常认真。
这个项目的整体结构大家可以先看一下,其中XUnit项目就是单元测试项目。
图1、解决方案结构图
其中的单元测试Case进行了一定的组织,相应工程的Case放在了不同目录下。
当然,这个大家可以根据具体情况自行确定组织方式。
对UnityHelper的单元测试
这个项目选用的依赖注入工具为Unity(
1/**********************************************************************
2*
3*北京航空航天大学计算机学院软件工程研究所AllRightsReservd
4*
5*任何拷贝都不允许删除此处版权声明
6*
7*作者:
张洋
8*
9*建立时间:
2010-01-08
10*
11*********************************************************************/
12
13usingSystem.Configuration;
14
15usingMicrosoft.Practices.Unity;
16usingMicrosoft.Practices.Unity.Configuration;
17
18namespaceSPMS.Common.Utils
19{
20///<
21///工具类
22///封装了Unity中Container的创建工作,并保证UnityContainer的单例性
23///<
24publicclassUnityHelper
25{
26privatestaticIUnityContainer_container=null;
27
28///<
29///获取UnityContainer
30///<
31///<
returns>
全局唯一的UnityContainer实例<
/returns>
32publicstaticIUnityContainerCreateContainer()
33{
34if(null==_container)
35{
36_container=newUnityContainer();
37
38//从配置文件中读取IoC配置信息
39ExeConfigurationFileMapmap=newExeConfigurationFileMap();
40map.ExeConfigFilename="
unity.cfg.xml"
;
41Configurationconfig=ConfigurationManager.OpenMappedExeConfiguration(map,ConfigurationUserLevel.None);
42
43//通过配置信息初始化Container
44UnityConfigurationSectionsection=config.GetSection("
unity"
)asUnityConfigurationSection;
45section.Containers["
defaultContainer"
].Configure(_container);
46}
47
48return_container;
49}
50}
51}
这段代码只有一个方法,就是CreateContainer,其作用是获取全局唯一的UnityContainer实例。
在写完这个代码后,我开始写单元测试,我能想到有四个点要测:
1)能正确返回UnityContainer
2)返回的UnityContainer能正确创建对象
3)保证创建的UnityContainer是单例的,即全局唯一实例
4)返回的UnityContainer在创建配置为单例的对象时,返回的对象应该是单例的
有了这四点想法,我写了如下的单元测试:
13usingNUnit.Framework;
15usingSPMS.Common.Utils;
16usingSPMS.Repository.IRepository;
17usingSPMS.Services.IServices;
18
19namespaceSPMS.XUnit.CommonTests
20{
21///<
22///UnityHelper的单元测试类
24[TestFixture]
25publicclassUnityHelperTests
26{
27///<
28///测试获取Container是否正常
29///<
30[Test]
31publicvoidTestCreateUnityContainer()
32{
33Assert.IsNotNull(UnityHelper.CreateContainer());
34Assert.IsInstanceOf(typeof(Microsoft.Practices.Unity.IUnityContainer),UnityHelper.CreateContainer());
35}
36
37///<
38///测试Container创建对象是否正常
39///<
40[Test]
41publicvoidTestCreateObject()
42{
43IRoleRepositoryroleRepository=UnityHelper.CreateContainer().Resolve<
44Assert.IsNotNull(roleRepository);
45Assert.IsInstanceOf(typeof(SPMS.Repository.NHibernateRepository.NHRoleRepository),roleRepository);
46
47IRoleServicesroleServ=UnityHelper.CreateContainer().Resolve<
48Assert.IsNotNull(roleServ);
49Assert.IsInstanceOf(typeof(SPMS.Services.ServicesImpls.RoleServicesImpl),roleServ);
51
52///<
53///测试Container是否是单例对象
54///<
55[Test]
56publicvoidTestSingletonContainer()
57{
58Assert.AreSame(UnityHelper.CreateContainer(),UnityHelper.CreateContainer());
59}
60
61///<
62///测试指定为Singleton的实例,是否为单例对象
63///<
64[Test]
65publicvoidTestSingletonObject()
66{
67Assert.AreSame(UnityHelper.CreateContainer().Resolve<
(),UnityHelper.CreateContainer().Resolve<
());
68}
69}
70}
即使你没用过NUnit,我想这段代码也是非常好理解的。
限于篇幅,不能详细介绍NUnit,这里只简要说一下。
使用NUnit首先要添加对nunit.framework.dll的引用,然后引入NUnit.Framework命名空间,最后,每个测试类添加[TestFixture]Attribute,而每个测试方法添加[Test]Attribute,这样就可以在里面写测试代码了。
其中用的最多的是NUnit.Framework.Assert类,它有很多静态方法用于断言,这些断言就是你期望的行为。
例如,Assert.AreSame方法断言两个变量是否引用同一个对象,我在上面代码里使用这个方法断言UnityContainer对象的单例性。
完成这个单元测试代码后,要把测试需要的配置文件等添加到XUnit工程里,我这里包括一个unity.cfg.xml,作为Unity的配置文件。
下面,编译这个工程。
如果编译没有错误,下面就可以跑这个测试了。
怎么跑呢,当你安装NUnit时,会同时安装一个NUnitGUI,在开始菜单中找到打开,界面大约是这样子:
图2、NUnitGUI
选择菜单栏的file->
openproject,打开刚才编译好的SPMS.XUnit.dll,也就是测试工程的dll文件,GUI会自动加载所有测试用例,如下图所示。
图3、加载工程后的NUnitGUI
OK,我们要测试的是Unit
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 单元测试