如果你愿意,你可以手工设计和运行单元测试,但这是低效和让人恐惧的。目前,各个平台上都有较为流行的自动化单元测试工具,像Visual Studio 2008本身就集成了单元测试功能。但是,我更愿和大家分享的是一个叫NUnit的工具。其官方网站为:http://www.nunit.org/。这是一个开源且免费的.NET平台下自动化单元测试工具,可以在其官网下载。NUnit是XUnit家族的一员,其体积小巧,使用简单,但功能强大,一直是我做单元测试的首选。
另外,这个例子我选取目前我正负责的一个实际项目,这是一个国家863项目。这个项目使用了敏捷开发方法,贯彻了以保证为目的的测试驱动、持续集成等实践。我将截取其中几个片段和大家分享一下单元测试的一些实践。
值得一提的是,我对这个项目的单元测试要求是相对严格的,我们使用的配置管理工具是SVN,作为项目负责人,我对所有开发人员有一个要求:每一个新开发的Class,必须有配套的单元测试,并且在每次Commit到SVN前,不仅仅要保证Commit的代码编译没问题,还要跑通所有单元测试,否则不准Commit到SVN。这就保证了每个人Update到的Class都是行为正确的。再配合面向接口编程方法和Mock技术,大大提高了代码的可测试性,使得开发过程一直比较让人满意。刚开始大家觉得我的要求有些过分,但是当每次结合时几乎都没有出现问题,每次刚刚集成的新功能都能顺利在UI上跑通,大家也就慢慢接受了,并且渐渐都对待单元测试非常认真。
这个项目的整体结构大家可以先看一下,其中XUnit项目就是单元测试项目。
其中的单元测试Case进行了一定的组织,相应工程的Case放在了不同目录下。当然,这个大家可以根据具体情况自行确定组织方式。
对UnityHelper的单元测试
这个项目选用的依赖注入工具为Unity(http://www.codeplex.com/unity)。因为获取UnityContainer是一个常用操作,所以我将其封装成一个辅助类,代码如下:
1 /********************************************************************** 2 * 3 * 北京航空航天大学计算机学院软件工程研究所 All Rights Reservd 4 * 5 * 任何拷贝都不允许删除此处版权声明 6 * 7 * 作者:张洋 8 * 9 * 建立时间:2010-01-08 10 * 11 * ********************************************************************/ 12 13 usingSystem.Configuration; 14 15 usingMicrosoft.Practices.Unity; 16 usingMicrosoft.Practices.Unity.Configuration; 17 18 namespaceSPMS.Common.Utils 19 { 20 ///<summary> 21 ///工具类 22 ///封装了Unity中Container的创建工作,并保证Unity Container的单例性 23 ///</summary> 24 publicclassUnityHelper 25 { 26 privatestaticIUnityContainer _container=null; 27 28 ///<summary> 29 ///获取Unity Container 30 ///</summary> 31 ///<returns>全局唯一的Unity Container实例</returns> 32 publicstaticIUnityContainer CreateContainer() 33 { 34 if(null==_container) 35 { 36 _container=newUnityContainer(); 37 38 //从配置文件中读取IoC配置信息 39 ExeConfigurationFileMap map=newExeConfigurationFileMap(); 40 map.ExeConfigFilename="unity.cfg.xml"; 41 Configuration config=ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None); 42 43 //通过配置信息初始化Container 44 UnityConfigurationSection section=config.GetSection("unity")asUnityConfigurationSection; 45 section.Containers["defaultContainer"].Configure(_container); 46 } 47 48 return_container; 49 } 50 } 51 } |