现在在公司里写没有要求用到测试,空余时间想学点新的东西。
好像好的写代码习惯是 测试和代码 1:1..但作为个新手真不知道测试好在哪里,多花那 1 份的时间值在哪里....
举点形象的例子,或者自己的亲身经历跟我讲讲么..
#1 楼 @lihuazhang 测试就是模仿在应用里的操作,而且尽可能考虑到所有在操作中出现的情况都写进测试?如果能写代码的时候严谨的考虑各种情况,效果也是一样吧?这样还真感觉测试有点不值呢..
前几天要改一个别人写的老方法,这个方法的上下文又比较多,全理清臣妾做不到,就是看测试代码理解这个方法的意图,通过跑测试确保我的改动没影响到别的功能。
所以我认为测试用处一是确保你的代码符合整个项目的预期,二是给后来的维护者说明你要解决的问题(因为文档咱们是不会好好写的,哈哈。文档没有动力维护,但是为了跑通测试你会主动维护测试的)
例如,升级 Ruby 版本,或者升级 Rails 版本的时候,或者升级某个 Gem,只要跑一下测试,就知道哪些地方不兼容,需要调整。
这个时候,如果人肉测试是要人命的。
#3 楼 @piecehealth 我明白了。另外关于文档,怎么都这么说啊,哈哈,上次一个朋友跟我说老板看到他写的文档后,问他小学语文老师是不是修锅炉的教的...
我觉得测试最大的意义在于添加/修改/删除一个功能后能尽量保证不影响别的功能。项目中相关的功能可能会很多,每次写完代码后要把相关的地方都手动测一遍很累也容易漏掉。
现在我们公司就是没有测试代码,所有的修改都是人测。 五六万行的代码,每次完整测试一次都要三周。
举个刚遇到的问题。 Ticket 1: Windows 服务器用户名不应该接受非法的字符,例如 " ' / \ ? 等等特殊字符。
于是我加了代码,在 3 个 model 的 5 个判断处加上了 raise error if username =~ /.../.
Ticket 完成了,QA 输入了一个非法字符,成功拿到了错误提示,搞定。
真搞定了吗?没有。
第二周客户拿新版本去用,然后就遇到问题了。 Windows 服务器的用户名可以用反斜线分割域名和账号。 ↑看上面,我们把反斜线禁用了。 客户非常愤怒,让我们赶紧修。 Ticket 2: Windows 服务器用户名处无法输入 域名\用户名
于是我打开源代码,找到了正则表达式,去掉了反斜线。 随便测了一下,哦可以用了,搞定。
真搞定了吗?没有。
过了两天我们一个 Dev 来找我,说你这正则出现了 5 次却只改了 3 个地方啊……
噫 Ticket 3: ……
最近因为某些事情,需要重构公司的电商网站后台,从 node 迁移到 Rails,因为逻辑先于代码产生,自然的就开始 TDD……没错测试在重构的时候可以起到至关重要的作用,但测试不仅仅是一种检查代码的工具,更是一种工作流程,比如常说的 TDD、BDD,测试是下一步开发的开始,也是这一步开发的总结,通过测试很容易得到文档……
当然还有一种情况……比如我懒得写 UI 手测了,于是顺手写了几行测试跑通就好啦……
1 减少手工测试时间 通常写了一段代码,如果手工测试的话,得启动应用、登录、制造测试数据、人工验证结果。这时如果写一个单元测试,就省事多了。
2 有效避免引入 Bug 在开发新功能时,针对新功能,其实很难引入 Bug,因为开发人员会手工测试,可能还有会专门的 QA 进行测试;但却非常容易破坏原来的功能,QA 通常会问 Dev,你告诉我重点要测试哪些功能,Dev 通常会说,你还是全部测一遍吧。而如果有测试代码,就可以在编码过程中频繁地运行,在引入 Bug 的第一时间察觉到,从而将修复 Bug 的成本降到最低。
3 可以运行的活文档 看产品代码时一般很难看出业务规则,如果有测试代码,test case 的名称也比较好的话,就可以当文档来读了,并且如果对某段代码有疑问的话,可以很容易地修改或增加测试来验证自己的想法。
4 提前搞清需求细节 如果进行 TDD 的话,需要在开始编写产品代码前就要分析需求,设计测试用例,可以帮助开发人员提前搞清楚需求细节,而不是写一会儿发现一个问题又去问产品经理(这样对开发的效率影响是很大的)。
想写这么多,想到再补充。
我也讲两句自己对测试的感受。
重构
原来带一个大部分是实习生组成的团队的时候,项目进行一个月的的时候,项目的代码简直不能看。我有心重构却不敢下手(真的可以体会到什么叫牵一发而动全身)。然后选择和团队老人一起做出各种测试的规范例子,让大家一定要 ShowCase 的时候不仅 show 功能还必须检查测试是否到位、规范。至少逐渐有了测试之后,我至少可以对某些不好的地方大胆放心的重构,那个感觉很爽。
理解代码
前段时间做一个 Ember 的插件,做了半年之后,发现自己以前写的代码不认识了,这个时候测试帮助我快速地理解这段代码。有时候去读一些其他人写的东西,尤其是一些文档更新跟不上的项目,规范的测试是一个不错的入手点。
代替文档
我的团队没有达到使用测试当做文档的地步,但是坐在我们旁边的团队确实做到了。在我们埋头写 github 的 wiki 时候,其实心里羡慕死他们了,不用刻意去维护文档。他们前端基本都不问后端接口的事情,直接看测试便知道。
保护现有功能的正常运行
重要的话说三遍! 一个爱折腾的人必须写测试! 一个爱折腾的人必须写测试! 一个爱折腾的人必须写测试!
先写这么多吧。
如果不在乎程序是否正确运行,重构之后也不在乎功能是否和原来一样,有了 bug 又不用(你)修,写测试就一点意义都没有了。
写测试是因为我在乎代码的功能是什么,如果不在乎的话,就不用写了啊。
既然说到“多花那 1 份的时间值在哪里” ,那我就从时间成本方面着手分析一下。
我的理解不是狭义的“用工具进行自动化测试” ,而是“检查软件功能是否运行正常” 。我们写代码的过程中,经常会刷新一下页面点一下功能,或者在 Rails console 里手动调用方法看结果是否正确。这其实也是测试的一种表现形式(手动测试,也称肉测……)。从这点来说,测试无处不在。因为你总要验证你的功能是否正确,对吧?
既然测试这件事情是必做的,那我们思考的就不是“测不测”,而是“怎么更有效率地测” 。测试一般发生在代码修改之后(没有修改自然不会引入新的错误),所以保险起见,我们应该在达到一定量的代码修改的时候,把被影响的功能全部测试一遍。问题是:
肉测是回答不了以上两个问题的。人做重复劳动是非常低效且容易犯错的,而且在大量重复劳动下很容易草草了事,比如“我觉得这个改动应该对功能 A 没什么影响,不测也行”。这会产生一些明显的或潜在的 bug,成为以后开发过程的拖累。
一定要做而且重复的工作,自然是交给计算机做更好。测试就是这类工作。以此类推的还有部署,数据库备份,代码风格检查等等。为一个功能写测试代码,第一次会花时间,但以后就可以非常快速地检查这个功能是否正确,在项目变复杂后也不用担心添加新功能或者重构会不会破坏已有的功能。不然的话,有可能后续一个开发周期有 1/3 的时间分配给改 bug,这效率能高到哪儿去?退一万步来说,就算维护测试的时间跟改 bug 的时间相同,我也愿意花了时间换来的是一个清晰可维护的系统,而不是补丁打满暂时能跑的系统。
从上面的分析来看,开发周期不长,功能不复杂,并且开发完成后就可以撒手不管的项目是可以不写测试的。因为你的测试过程不会重复很多次,代码产生的修改也是有限的。不过我真不建议你这样做,因为:
这跟写代码的方式有关,相比写测试,我更愿意在写代码之前多思考一下。 还有就是大家要严格按规则写代码,我见一大批人,测试挂嘴边,然后等代码 提交上来。自己以前的测试都不过。
偶觉得测试是为代码服务
测试驱动开发是学院派的臆想,现实中的需求可不仅仅是删帖、回帖、编辑这些简单的操作。现实中的需求如果全用测试模拟出来,会比开发项目本身还复杂,10 个人开发的项目,可能需要 20 个人去开发测试程序,不如雇佣 5 个人手工测试合算了。
多数时候测试更像是一个说明书,说明了功能代码的使用方式,会产生什么样的结果,这个时候看测试代码就能很快理解功能代码的意图,所谓的 TDD 就是干这个事,一般也就做到这个程度了; 至于保证程序健壮性的测试,那么必须对边界条件非常清楚,而且保证测试代码覆盖到所有可能的情况(理想状态),这种意义上的测试,成本就很高了,得看项目的性质,是否值得这么干
曾经深入接触过专业测试团队,200 人以上。 其实,把测试理解成信仰,总体来说有点过了。不过对程序员来说,也无可厚非。 作为软件生命周期的一部分,测试不能少,就像我们人类正常生命中,不能缺少钙元素一样。测试,类似体能锻炼,这样才能保证钙元素的充分吸收和循环。
#28 楼 @hi2016 这是因为你没有做好 Isolation,而不是测试本身太难写。推荐去看看 https://www.destroyallsoftware.com/screencasts
测试驱动能在开发的时候指导你设计接口,因为写测试必然先写怎么用调用接口,然后再实现它,这样能防止写出翔一样的接口。 重构时,重构没有改变代码行为的依据。 修改 bug 时,先写 bug 复现的测试,再解决 bug,有效保证以后的代码修改引入同样的 bug。
先想到这么多,最后,相信我,写测试的时间远低于今后你为了测试同一个地方的可用性而进行的手动测试的时间。
测试对于程序来说,不是必不必要的问题,而是怎么测的问题。就算不写测试,你一样在人肉测试。只不过人肉测试效率太低,出错率也高,对于中等和以上规模的程序,需要写测试来代替人肉测试,以减轻工作强度罢了. 功能和代码不断的扩充,不断重构和优化,这个过程中,没有好的测试,基本就掉入修 bug 泥潭了。有话说改一个 bug 带来 3 个 bug, 自动测试一定程度上可以减轻这个状况。 总之,逻辑简单,或者写完没有更改的必要,类似这种代码人肉测测也无可厚非,逻辑稍微复杂的,以后更改的可能性存在的,那么自动测试毫无疑问是必要的。
简单说,我觉得至少有三点:
测试可以模拟条件和输入输出,让你不需要运行程序,不需要打开额外窗口,不需要用鼠标或者键盘去交互,就能知道模拟出来的结果。这比人工测试快很多。比如说你想测试下密码组合的验证模块,你认为是用测试代码来获取结果方便,还是人工往密码框里输入各种组合方便?
假如你的软件涉及到生命财产安全,举个极端的例子,例如火箭发射或者医疗器械的软件,你觉得可以不测试,然后出了问题再修???
白盒测试可以给你代码覆盖率,让你对自己的代码执行流程有个更深的了解。可以发现更多潜在的 bug,漏洞和无用代码。
有一种情况下不用测试,就是程序很小,只有一种输出。那你跑一遍然后看下结果就可以当成是测试,也就不需要测试代码。
多写测试少加班