已锁定 主题: 程序员为什么不写单元测试
该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2007-07-10
public void testRecordListAveragePrice() { RecordList recordList = new RecordList(); Record apple = new Record(); apple.setSellingPrice(15.0); recordList.add(apple); recordList.fillTprice(); assertEquals(15, apple.getTprice()); } 一句代码都不要写;(自动生成的就能通过。。。真不爽。) 重点:不要考虑flage的影响 public void testRecordListAveragePrice() { RecordList recordList = new RecordList(); Record apple = new Record(); apple.setSellingPrice(15.0); recordList.add(apple); recordList.fillTprice(); assertEquals(15, apple.getTprice()); //上面的不是重点 下面是新加入测试 Record bicke = new Record(); bicke.setSellingPrice(25.0); recordList.add(bicke); recordList.fillTprice(); assertEquals(20,apple.getTprice());//注意一下这里用的是apple } 改到代码能用为止 |
|
返回顶楼 | |
发表时间:2007-07-10
抛出异常的爱 写道 “代码:”
是代码应该完成的事。 本应该是设计师的活。 在TDD中这种详设被溶入了测试的编写之中 “测试驱动:” 是业务的实际意义,这都是非编程人员,提出的需求。 就是由需求直接变代码的过程。 现实中会到例子。 你的观点我很多都不认同。 系统整体架构的设计呢?设计师并没有在这个过程中消失,只是设计师负责的是比程序员更高一层的设计,在细节处理(也就是局部代码的设计)上把权力下放给程序员。而设计师(一般为敏捷团队的队长级人物)要负责把需求分析出来,并写出用户故事,这些什么可能的分支,意外的情况啊之类的也需要设计师来做第一次决定,程序员有一定权限来添加这些情况和分析需求,程序员主要还是负责对用户故事的实现,当然这是在一个良好沟通的环境下(敏捷环境)。 而对于一个测试,写出来之后的首要任务是让他通过,如果通过ide的自动生成代码可以通过测试,这是一件值得高兴的事,因为green bar出现了。“不可以运行,可运行,重构”这是TDD的口号啊。重构的工作应该在伪实现之后马上进行,而不是等到需求变化那么久远的事情。重构的目的就是消除代码的坏味,坏味哪里来?测试驱动的提出者K.Beck说是代码重复,伪实现里代码的最明显的重复代码就是那些伪实现里的常量。由此重构开始。 每个逻辑能不能分解呢?虽然你认为一个只有一句的逻辑不叫逻辑,但是再复杂的业务逻辑也是由一堆简单的逻辑组合而成的,那要让代码让测试目的简单明确是不是就要对逻辑进行分解呢?分解之后的简单逻辑,就是一两句。你有没有看过K.Beck的TDD原书,他在一个业务场景中写了很多你认为不是逻辑的逻辑,都是一句,比如“5美元+5美元=10美元”,“5美元+10瑞士法郎=10美元”。 至于你提到的每次需求变化时,测试需要改动,这很正常,测试代表的逻辑就是用户故事,但是你说的代码要做大改动的问题就是你的编码的问题了。面向对象的设计应该遵循OCP原则,对扩展开发,对修改封闭。R.C.Martin在《Agile Softwate Development》说过一句很经典的话,“你不能被同一把枪射中两次”,意思是面对了第一次的需求变化时,你就要重构代码,让代码能够适应同一类变化,让代码遵循OCP原则。 重构什么时候开始?《Refactoring》中说,随时都要重构,需求一直变化,今天的优美的设计可能到明天就变得笨拙了,应该一直重构,让代码简单清晰。 |
|
返回顶楼 | |
发表时间:2007-07-10
你引用了不少的精典例子;
1.我问如下的问题: 设计师是干什么的呢? 你公司有没有设计师呢? 你会发现根本没有多少是必须由设计师来作的事。 程序员正在完成这类的工作。 而必须由设计师来做决定的事大多不是由于技术原因。 2. 自动生成代码可以通过测试? 是的。这不好,所以要加入另一个例子。这个例子才是主要的。 这也是不新开一个测试的原因。 3. 小逻辑也是逻辑,1+1=2这样例子能表达什么样的效果。。。? 我要写一个复杂一点点的逻辑主要是让看的人有真实的感觉,不是那么枯燥。 客户就是这么要求的。 4. 如果测试用例变了之后代码不变的例子很少 。。。当然你重构了之后,测试用例的变化对代码的影响会变小。 不重构的话,一个逻辑的这里一点需求变更,那里一点需求变更代码就会变成粥。 重构是下一节课的问题。 -------------------------------- public void testRecordListAveragePriceExceptNoPayOrder() { RecordList recordList = new RecordList(); Record apple = new Record(); apple.setSellingPrice(15.0); apple.setFlage(true); Record bike = new Record(); bike.setSellingPrice(25.0); bike.setFlage(false); recordList.add(apple); recordList.add(bike); recordList.fillTprice(); assertEquals(15, apple.getTprice()); } 代码写了; 通过了测试3; 但是测试2不能通过了。。。。 左看右看。。。 测试写的有问题 flage没有被初始化 改之: 略 再来。。。。2过,3过。 是否有问题? 对。。。 测试代码需要重构 |
|
返回顶楼 | |
发表时间:2007-07-10
异常的爱,很不好意思,又跟你的意见不统一了。
个人以为,把测试代码看成与源代码性质一样的“代码”, 是不成熟的。 测试,不是代码,而是一种质量标准,一种保障! 一个好的项目架构,如果有足够全面的测试类,那么整个团队的负担都会减轻很多。 我认为,一个逻辑再小,只要不是getter/setter,也要写个test case. —— 反对派会问:“你时间很多么?有必要么?”——很有必要。无数个这样的Test Case, 就组成了整个系统持续构建的Test suite. 使用ant 每隔几分钟run 下吧。 不写测试,或者找种种借口的人,招聘时我是不考虑的。 另,招聘时考虑的一个重点,就是看他的测试用例写的怎么样。 |
|
返回顶楼 | |
发表时间:2007-07-10
我只是一个还在死读书的学生,不然就不会那么快得举出例子来了^_^平时只是和同学在玩玩敏捷游戏,做做一些小小的应用。只是看到你讲的事情和书上写的和我自己在网上看到的一些人的理解不同,所以就出来胡说一下。相信你的项目经验比我多n倍,是我不可以匹及的。
这些测试不是给客户看的吧?给用户看的应该是在用户指导下写出来的用户测试吧,也就是每次交付时,对集成的系统的一些测试。用户没有必要直接看到代码吧,只要完成了用户提供的需求就够了,软件的核心目的也就是如此。 我还是坚持认为代码的重构应该在第一测试通过后,测试驱动的第一个好处就是可以在编码过程中加深对用户需求的理解,第二个重要意义就是可以让你有信心地重构,因为你刚刚写出来的测试可以为你报价护航。而且重构是要细粒度,小步伐的进行,因为太大的步伐,很容易就让你写出了一些不能通过测试的代码。这就是很多人都说,包括gigix,说:“重构很琐碎”。 我对gigix在序里说的“变得像空气和水一样普通的技术”,很有感受,TDD,重构就是这样子。 |
|
返回顶楼 | |
发表时间:2007-07-10
sg552 写道 异常的爱,很不好意思,又跟你的意见不统一了。
个人以为,把测试代码看成与源代码性质一样的“代码”, 是不成熟的。 测试,不是代码,而是一种质量标准,一种保障! 一个好的项目架构,如果有足够全面的测试类,那么整个团队的负担都会减轻很多。 我认为,一个逻辑再小,只要不是getter/setter,也要写个test case. —— 反对派会问:“你时间很多么?有必要么?”——很有必要。无数个这样的Test Case, 就组成了整个系统持续构建的Test suite. 使用ant 每隔几分钟run 下吧。 不写测试,或者找种种借口的人,招聘时我是不考虑的。 另,招聘时考虑的一个重点,就是看他的测试用例写的怎么样。 这位大叔和我的看法比较相同。 对测试覆盖度的问题,在ibm developerWorks上有几篇讲代码质量的文章,就讲到了对测试覆盖度看法,对于每行代码都覆盖到的测试不一定就是好的测试,还有也提到了如果不是自动代码生成的是手写的getter/setter也需要测试,只要是人手写出来的代码就有可能出错。 还有对于Test suite我有个疑问,你的系统几分钟就可以跑完所有测试?那你的系统不是很大了,Test suite没有对包或者是对架构层进行划分?忘了在哪里看到一篇文章,讲的就是对Test suite的包划分,把Test都分类,在进行较高层次的重构时,只要运行对应的子Test suite,就可以对重构进行保证,比如在两个模块之间进行,职责划分修改的重构,就是把一个模块的其中一个职责移动到另一个模块中的时候。 我会把你上面的话改一下,使用构建工具在每次重构和集成时运行TestCase吧! PS:现在国外的很多开源项目开始由使用ant构建改为maven构建。虽然maven的自动依赖库下载功能还是有些问题。 外话: 看看我在上一页写的测试能不能通过大叔你的面试 |
|
返回顶楼 | |
发表时间:2007-07-10
项目没有明确的指导,技术leader也好,项目经理也好,很多公司都不关心你做的软件有多健壮,以后的开发能用到多少。
所以没有单元测试是再正常不过的了,因为没有人关心他,程序员不会因为把单元测试做的好,而获得而外的项目时间,久而久之,就养成了习惯。 |
|
返回顶楼 | |
发表时间:2007-07-10
to chenk85:看来现在的在校大学生也不全都在玩游戏阿,佩服佩服,你对敏捷方法的理解已经超过很多工作多年的程序员了
btw:好测试的标准之一就是能快速运行,据说springframework就可以在几分钟跑完它的上千个测试 |
|
返回顶楼 | |
发表时间:2007-07-10
daquan198163 写道 to chenk85:看来现在的在校大学生也不全都在玩游戏阿,佩服佩服,你对敏捷方法的理解已经超过很多工作多年的程序员了
btw:好测试的标准之一就是能快速运行,据说springframework就可以在几分钟跑完它的上千个测试 过奖了。以后出去不知道还能不能找到好工作。 和一开始就认为“程序 = 数据结构 + 算法”的多年程序员比的话(学校里的老师也是整天叫嚣着这个),可能是这样,而我是一开始就接触OOP,然后是OOA/OOD,接着就是敏捷。敏捷把OOP和OOA/OOD等的概念都具体化了,而且概括性地提出了把OO应用到实际开发活动中,比如TDD实践。 PS:spring的测试好像都编译不过,报了很多错误。 |
|
返回顶楼 | |
发表时间:2007-07-10
chenk85 写道 对TDD来说,我自己已经开始习惯了这种编码方式,编码前写一个TODO-List,然后写TestCase,接着才有代码,再重构,最后有了代码。这样写相对于传统的编码来说,免去了一大堆Debug的时间,不然写完一堆代码,然后手动一测试,一堆Bug和非预期行为,接着就是无穷无尽的折磨人的debug时间来了。
有句话,“看起来很美” 虽然我相信真理的天平上,TDD比传统debug要重的多。 但TDD是全部么?完美的符合国情么?(架构设计、人员素质、进度压力) |
|
返回顶楼 | |