作者: 程序猿就是我 ,发布于2012-7-20 就要完成所有的单元测试的任务了,做了将近三个月的时间,如果放在以前我有一肚子苦水要述说,不过经历了一些思想上的洗礼之后,不在那么单纯,只为把手头工作做的更加出色而已! 这是单元测试最后一篇了,来做个总结把! 目录: 好的单元测试应该具有的特点 单元测试的命名规范 建立自己的公共调用库 单元测试带给我的思考和感悟 总结图示 1、好的单元测试应该具备的特点 一个好的单元测试一定有它具备的特点,下面就来说说那些主要的特点! 主要概括为 → A-TRIP原则: 自动化 → Automatic 彻底性 → Thorough 可重复性 → Repeatable 独立性 → Indepentdent 专业性 → Professional 恰到好处的单元测试会使你的工作轻松,代码整洁干净,乱用,没有准则的用会浪费你大量的时间,不但没有效果还会是工期延误,所有了解单元测试很重要! ① 自动化 a)不需要人的参与,有的时候只是轻轻的点击一个按钮就能自动执行,所以自动化的标志是不能比点击一个按钮的过程还要复杂! b)在签入其它的测试代码时不能对现有的代码造成影响! c)能够自动识别测试是失败还是成功(VS2008以后的版本都集成了这个功能)! d)在任何时候,任何地方都能自动运行(所以“Moles”技术就是关键)! 核心:执行测试代码和检查测试结果都必须自动化(VS2008以后版本都实现这个功能了)! 总结:I,不要引入一个由于需要手动步骤而打破单元测试的自动化模型的测试! II,对于测试所需要的任何条件(大部分是数据库)都应该让它成为自动化测试的一部分,如果有需要可以使用Mole技术! ② 彻底性 所谓的彻底性就是说你的测试案例必须要考虑的全面,应该把可能出现的问题都做成测试案例! 具体从哪些方面着手,可以参阅这篇:走进单元测试:测试需要从哪些方面着手 ③ 可重复性 a)每个测试案例应该独立于所有的其它测试,而且必须独立于周围的(系统)环境! b)测试代码能够一次又一次的运行,在不修改代码的前提下都能产生一样的结果,否则有BUG! c)不要把测试代码写死,应该写的更加灵活一点,运用封装,重构等等的思想! d)不要让测试本身也出现BUG,确保测试代码的正确性! ④ 独立的 a)每个测试应该有很强的针对性,也就说一个测试只能测试一个方面的内容! b)每个测试应该独立于环境(软件所处的系统环境)和其它测试! 总结:I,每个测试都不能够依赖于其它测试,你可以在任何时间运行这个测试而不受其它测试的影响,每一个测试都应该是一座孤岛! II,所以测试一个函数都有很多个测试方法,只有这样才是真正的测试! ⑤ 专业的 a)所谓的专业就是你的测试代码应该跟你的开发代码保持一样的风格,如:简洁明了,封装,解耦,不要出现“Hard Core”,要灵活一点! b)拒绝编写冗余的测试代码,千万要小心不要掉进这个陷阱,因为像我们这样的新手在初期都不会注意到这样的问题,所以我们要牢记在心里! c)遵循普遍规则:1.维护封装 2.降低耦合! 总结:不管怎么样你都应该认认真真的对待单元测试,代码的质量要求都应该跟开发代码同等水平,这是作为开发者必备的素质! 2、单元测试的命名规范 在我们项目的中,可能需要测试的方法有成千上百个,而每一个测试方法都有可能写三个以上的测试案例,那么怎么来维护这么测试案例呢? 所以我们应该规范方法的命名方式,那么其他人在阅读你的测试代码时,直接通过方法名就能知道你的测试案例是测试哪个方面的了! Note:单元测试案例类似于一个可执行文档,可以帮助其它的开发人员了解方法的作用! 在我们的项目中是这样规定的:方法名 + _ + 你测试是哪个方面的内容 + _ + 产生的结果! 下面我就举个列子,下面的测试方法命名就是针对这个函数来命名的,如: | public DataSet GetDetails(int ID) { // 方法的作用:这个一个获取数据,并包装成一个DataSet的方法,传入的参数是一个bondAppID, 那么我们怎么来设计案例和命名方法名呢? } |
① 首先设计你的测试案例 看到这个方法我就会有这几个想法:1,最大值 2,最小值 3,刚刚好的值 4,随便一个值 5,还有的测试案例会随着你代码中的逻辑而产生! 下面是我的测试案例以及方法名的命名,测试方法是上面的那个: | /// <summary> /// Input valid bond ,but the cheque is presented Status. ///</summary> [TestMethod()] //如果你预期有数据返回,那么就应该在最后面加上“RecordFound”,这样别人看的时候就能一目了然了! public void GetDetails_CheckPresentedStatus_RecordFound() { //To Do. } /// <summary> ///Cancel Status. ///</summary> [TestMethod()] public void GetDetails_CheckCancelStatus_RecordFound() { //To Do. } /// <summary> /// Input max. ///</summary> [TestMethod()] public void GetDetails_CheckDetailsByMaxBoundaryValue_NoRecordFound() { //To Do. } /// <summary> /// Input min. ///</summary> [TestMethod()] public void GetDetails_CheckDetailsByMinBoundaryValue_NoRecordFound() { //To DO. } /// <summary> /// Any bondID. ///</summary> [TestMethod()] public void GetDetails_CheckDetailsByAnyBondID_NoRecordFound() { //To Do. } |
② 说一下总的命名规范 a)如果返回值是“Bool”型的话,应该在最后面加上“RetrunTrue”或“ReturnFalse”! 如:CheckRebateHasNewChange_ExistNewChanges_ReturnTrue b)如果返回值是集合或者DataSet之类的类型话,应该在最后面加上“RecordFound”或者“NoRecordFound”! 如:GetPurchaseOrder_ByPurchaseOrderId_RecordFound c)如果是测试异常的话,应该在后面加上“ThrowException”! 如:CreateRebateApplication_ExistSameRebateID_ThrowException d)如果是岁数据库进行删除或者更新,插入的操作时,应该在后面写上“DataUpdated”或“NoDataUpdated”! 如:UpdateClientIncome_UpdateIncome_DataUpdated 总结:基本的变动部分都是你中间的描述,中间的描述尽量做到简洁明了,应该以动词开头,如:Update,Input,等等! 总结:好的命名方式可以增强代码的可读性,尤其是类似于单元测试这样的可读性文档,应该更加注意这方面的考虑! 3、建立自己的公共调用库 一个好的单元测试应该都有自己的公共调用库,这样能减少很多的冗余代码,使的代码简洁易懂! 所以建立了公共库的单元测试符合了单元测试特点中的专业性 → 1.维护封装,解耦等等特点! ① 建立数据库访问库 测试中的准备数据从何而来,有的时候数据准备比较简单,那么如果传入的参数是DataSet的呢,里面的数据比较多呢,或者更新数据库呢,我们应该怎么做? 那么我们应该去数据库中查找数据,然后在组合到DataSet中去,所以建立必要的数据库访问类很重要! ② 建立自己的公共库 这些是为了你验证数据,或者搭建环境等等的一些用处,提高编写测试代码的速度 这是我们建立的公共调用库,所以如果建立了库,对于我们的单元测试将是大有裨益的! 4、单元测试带给我的思考和感悟 ① 感悟 说实话从一开始做单元测试的时候,我对它真的很鄙视,我觉得它的含金量很少,编写单元测试代码太枯燥了,导致了那时候我的心态是多么的浮躁,以至于在思想方面出现了偏差,感兴趣的朋友可以看看这篇文章 → 工作的思考,是走还是留! 经过一段时间的自我反省,也确实让我慢慢的走上了正轨,感兴趣的朋友可以看看 → 迷茫后的感悟! a)做任何一件事都应该专心,戒骄戒躁,这是我深有体会的! b)事无大小,不要认为你的事很无聊,很枯燥,很不值得一提,但是一旦你做好做精之后你就发现原来你不知道的还有这么多啊! c)努力 + 学习方法 + 工作态度 → 是我这段时间感悟比较深的一件事! ② 思考 前提:我们做的单元测试是在项目后期写,而且我对我负责的模块是一窍不通的(我是刚刚进这个项目组的),业务流程根本不懂! 在这样的前提下,每天先熟悉下流程,看一下代码,找带头大哥帮我讲解讲解,然后才开始写单元测试代码,由此我有了下面三点的思考: a)单元测试不应该在后期做,应该在项目的开发时期去完成它,这个可能跟我们的项目本身有原因把! b)对于找一个还不懂业务流程的人来做单元测试自我感觉是有点不合理的,至少会花费更多的时间来熟悉流程。然后再做单元测试! c)项目过程中的代码编写习惯也是很重要的,这是我应该要加强和思考的,也是我需要培养的习惯! 5、总结图示
|