开发人员必备的技能之单元测试(4)—Android开发进阶

发表于:2016-6-23 09:12

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:何红辉    来源:51Testing软件测试网原创

  第9章  开发人员必备的技能-单元测试
  学校里软件工程专业的同学可能都学习过软件测试这门课,在这门课中我们会学习单元测试、集成测试、黑盒测试白盒测试等。我们这里并不是要重新学习这些分类繁多的测试,而只是着重学习单元测试。因为只有单元测试是我们开发人员需要自己完成的,其他的测试类型则是由测试人员进行验证。在大学的课堂里,虽说我们学习过单元测试,但是由于缺乏工作经验以及思想指导,所以,并不能体会单元测试给我们带来的好处,只能明显感觉这又增加了工作量,因此,绝大多数开发人员并不会将单元测试纳入工作范畴,也就是说不写单元测试用例。还有很多开发人员甚至不知道单元测试是什么,因此,在本章将学习单元测试以及它在开发中的重要作用。
  9.1 什么是单元测试
  单元测试从本质上讲也是代码,与普通代码的区别是,它是验证代码正确性的代码。因此,可以给单元测试做个简单的定义:单元测试是开发人员编写的、用于检测在特定条件下目标代码正确性的代码。
  软件开发具有天生的复杂性,没有人能做到不测试就能够保证代码正确运行。在正常执行路径下能够执行,但是在其他路径就未必可行。此时,我们关注的只是程序的正确性,以保证程序在各种环境之下具有正确的行为,因此就需要我们对代码进行严格测试。那么现在问题来了,单元测试能够给我们带来哪些好处呢?
  9.2为什么要做单元测试
  做任何工作通常会考虑它的回报,编写代码更是如此,如果单元测试作用不大,没有人会愿意额外地再写一堆无用的代码。那么单元测试到底能够给我们带来什么优点呢?笔者总结了有如下几点。
  (1)便于后期重构。用单元测试尽量覆盖程序中的每一项功能的正确性,这样就算是开发后期,也可以有保障地增加功能或者更改程序结构,而不用担心这个过程中会破坏原来的功能,因为单元测试为代码的重构提供了保障。只要重构代码之后单元测试全部运行通过,那么,在很大程度上表示这次重构没有引入新的Bug,当然这是建立在完整、有效的单元测试覆盖率的基础上。
  (2)优化设计。编写单元测试将使用户从调用者的角度观察、思考,特别是使用TDD(测试驱动开发)的开发方式,迫使设计者把程序设计成易于调用和可测试,并且解除软件中的耦合。
  (3)文档记录。单元测试是一种无价的文档,它是展示函数或类如何使用的最佳文档。这份文档是可编译、可运行的,并且它保持最新,永远与代码同步。
  (4)具有回归性。自动化的单元测试避免了代码出现回归,编写完成之后,可以随时随地地快速运行测试。而不是将代码部署到设备上,然后再手动地覆盖各种执行路径,这样的行为效率低下、浪费时间。
  上述4点虽说只是几句话的描述,但是给程序带来的影响是巨大的。良好的接口设计、正确性、可回归、可测试、完善的调用文档、高内聚、低耦合,这些优点足够我们对单元测试重视起来,并且在项目中进行实战。虽然前期可能会遇到一些困难,例如,不知道要测试哪些内容,但是,当你客服这些困难之后你会感受到单元测试带来的益处。
  9.3不写单元测试的借口
  很多开发人员不写单元测试,最重要的一个原因是他们并不知道单元测试能够带来什么好处,甚至根本不了解单元测试这个词,那自然就像平行线般与之毫无交集。还有一个比较重要的原因是一些开发人员的编程思想还处在一个相对初级的阶段,开发软件只管实现功能,什么高内聚、低耦合、重构、设计、可测试等都认为太过专业,对于这些名词以及意义还不了解,这自然不会考虑使用了。另外还有一些非思想层面的理由,主要有如下几个。
  1.单元测试太花时间了
  软件开发工作那么忙,代码都写不完哪有时间写单元测试!这可能是开发人员用的最多的借口了。从某些方面说,这不能算是借口,因为很多开发人员确实在工作上投入的时间特别多。
  但是真的是这样的吗?你有没有想过,导致你加班的原因也许就是你花了太多时间在手动测试、调试程序上;或许你没有考虑到灵活性与设计,使得在需求发生变更时你需要花很多时间在复杂的代码堆中完成特定的功能,而这些修改又可能引入新的Bug,又将导致你需要进行耗时的手动测试、调试……如此反复,代码将变得越来越乱、越来越难以维护,最终导致了无休止的加班。
  2.测试不是我的工作
  测试确实不是开发人员的工作,但单元测试确实是开发人员的工作。测试包含很多种,而只有单元测试是开发人员的工作范畴。开发人员为应用编写代码,那么自然需要保证代码的正确性。而单元测试正是这种保证代码正确性的白盒测试,也就是在了解代码内部逻辑的情况下进行的有目的的测试,说到了解代码,那么开发者自然是最权威的人。因此,编写单元测试并且为测试人员提交正确的代码进行其他测试是开发人员的职责所在。
  3.代码都编译通过了还测什么
  一般来说,这是一个不会放在嘴上但可能会藏在心里的借口。代码编译通过只能说是你的代码语法没有什么问题,但是,在正确性上并不能够保证。例如下面的代码会导致编译不能通过:
  publlc class MainActivity extends Activity {
  // 代码省略
  }
  稍微细心的读者可能发现了,这里将public写成了publlc,这类明显的语法错误能够被编译器捕获到,也就是说编译器只能从语法上给你找出问题。再看下面的例子:
  public int div(int a, int b ) {
  return a / b ;
  }
  这是一个除法函数,它能够正常编译、运行,但是在当b等于0时该段代码会引发异常,导致程序奔溃。也就是说我们要确保的是代码能够在各种条件下都能够正确运行,这些都需要我们进行测试,而不是拿编译通过来敷衍自己。
  4.代码原来就没有单元测试,且难以测试
  提出这问题的基本上都是接手和维护别人代码的开发者,而原来的代码本身没有单元测试,再加上如果代码的耦合性较高,那么就更难以为这些代码写单元测试了。此时也正是你了解代码的时候,首先为能够测试的部分添加单元测试,保证这些可测试的部分不会被污染。然后在对代码有了足够的了解之后对代码进行重构,降低代码的耦合性,并且慢慢补充测试用例,使得代码低耦合性、可测试性慢慢建立起来。
本文选自《Android开发进阶—从小工到专家》第九章,本站经人民邮电出版社和作者的授权。
版权声明:51Testing软件测试网获人民邮电出版社和作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。\
Service与AIDL(3)—Android开发进阶
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号