2024年2月21日

质量在于充分完备的测试,尽早发现问题

作者 柳 永强
内容目录

质量在于充分完备的测试,尽早发现问题

  任何软件产品,在交付给客户或者用户之前,必须经过严格并且充分的测试,由此才能保证软件产品功能可用,易用,并且能够可靠持续的提供服务。道理很简单,只有稳定可靠的软件服务才能在用户或者客户群里赢得良好的声誉,从而赚取更多的利润。相反随时崩溃的程序带给用户的只有极其差劲的体验,我想说只有傻瓜才愿意为这样的软件服务买单。如果你的软件面对的不是直接用户,而是中间的供应商,那么你就更应该保证软件的质量,在这种情况下,任何软件的bug都可能给你的客户带来极大的损失,你的公司也会因此丢失这样的客户,同时使你在同样的客户群中失去信誉,因此作为软件提供商,必须清醒的知道,应该用高质量的软件来成就客户才能赢得双赢的局面。

  软件测试如果按照测试阶段分类的话,主要分为单元测试、集成测试、系统测试和验收测试。其中单元测试按照测试方式的话,属于白盒测试,是程序员在写代码的过程中必须完成的测试,距离编码最近,是能够最早发现程序问题的一种测试手段。由于单元测试能够帮助程序员在编码的早期阶段发现问题,程序员可以快速定位到问题的根因,因此解决问题的成本几乎可以忽略不记。

  单元测试是保证程序质量的第一步,因此程序员对此必须要有清醒的认知,业务代码和单元测试的代码具有相同的重要性。

  在这里,我想用我的个人职业生涯的经历来说明,怎么做才是提高软件质量的正确做法。

  我硕士毕业后的第一份工作是在A公司,正是在A公司,奠定了我十多年软件职业的基础,但是在A公司工作的三年里,我甚至没有听过关于单元测试的任何讨论,我个人甚至没有接触单元测试的概念,在A公司,程序员们按照需求编写相应的软件功能,然后直接交给测试同事,由于编写的软件是windows界面,测试的同事们也不了解什么是自动化测试,以我现在的目光来看,在A公司,测试同事们使用最原始的方式进行测试,不借助任何工具。而程序员们只关注编码,测试并不是自己的责任。当你看到这里,也许你很好奇,以这样的方式开发的软件是否真的可靠?我的直观感受是,我们整个团队,其实对软件的质量并没有十足的自信,因为每次客户在使用我们的软件系统时,都要求我们有足够的技术团队的现场支持,我甚至好几次碰到过在客户现场,团队惊慌失措的解决临时问题,也许这问题就是个低级错误。

  我刚进A公司的时候,我曾经作为技术支持接手过一套软硬件系统,原作者在我进公司的不久前离职了,他是大家公认的牛人,写这套软件的时候据说是起早贪黑在很短的时间内快速完成了需求任务。提到这位同事的时候,公司的领导和其他同事都会眼前一亮,说他在写程序方面非常厉害,佩服的五体投地。而我一个新手可就没那么容易了,当我阅读他写的代码时,满篇的代码都是简写,简短的命名,没有任何注释,深度的嵌套,以及错综的分支,这样的代码很难说具有可读性。为了读懂和理解代码逻辑,我不得不找到硬件的开发文档,同时找了一台设备,自己手动测试加单步调试。我不得不说,这是一套复杂而脆弱的系统,因为几乎没有任何测试就交付给客户使用了。很多次我都是在现场解决一些奇怪的问题同时被一些客户破口大骂。对这样的程序员,我曾有过一丝的崇拜,可是当我在软件工程这条道路上逐渐成熟的时候,我意识到应该对聪明的程序员和专业的程序员加以区分,我觉得我的这位前辈只能归为聪明的程序员,而我更喜欢后者,坚持让自己逐渐成长为专业的程序员。

  当我意识到在A公司成长有限时,我毅然决定离开,选择了远在其他城市的B公司,B公司是国内比较大通信及软件供应商,具有完整的质量管理体系,领导层也具有远见卓识,是国内数一数二的技术型企业,正是在B公司工作的很多年里,让我深入接触了Linux 平台,在软件开发领域打开新的眼界,我的技术能力也得到了快速的发展。正是在B公司,我开始接触到单元测试和TDD的概念,同时我也开始听到了周围一些同事对单元测试的讨论。可是遗憾的是,我现在看来,我们当时的团队X在采用TDD开发模式上是失败的。团队在一开始软件开发时,就设定了单元测试覆盖率需要达到95%以上,但是由于团队成员资历尚浅,缺乏资深专家的正确引导,并没有严格的按照TDD 所谓的先写测试,后写业务代码的流程做开发,大部分的人还是先写业务逻辑的代码,然后再考虑UT覆盖,甚至很多人只是为了满足覆盖率,让用例蒙混过关。我身边所有的同事都认为,单元测试的代码是用来测试的,所以单元测试的代码质量并不重要,这导致团队开发人员对于如何写好测试用例根本没有认知。最后导致的结果是,单元测试没有帮助程序员有效的发现问题,反而成了项目维护的累赘。最典型的问题是当后期代码有任何变动的时候,导致很多用例失败,程序员在维护测试用例上花了很多成本。

  有趣的是,X团队里,起初大家认可单元测试的有效性,可是到后期就开始蔓延单元测试无用论。

  当我从B公司的X团队转到Y团队时,由于Y团队基于开源软件做开发,因为开源软件本身没有引入单元测试框架,因此大家写代码的时候索性都裸奔了,只是在程序员交付之前必须有手动的验收测试报告,程序员在设计软件过程中,需要设计自己的验收测试用例,然后手动执行,交付功能给测试人员时,需要保证验收测试用例全部通过。测试人员会再此基础上再做更加完备的测试。这套流程看似是严谨的,可是常常出现的情况是,程序员的验收测试用例时常设计的比较简单,为了应付交付的压力,验收测试用例基本上只保证了功能的可用,对于异常,性能和稳定性上缺乏足够的测试。同时还存在一个巨大漏洞是,当软件发生维护和变动时,因为缺乏单元测试的覆盖,对于那些解决老问题,引入的新问题很难快速发现,常常漏到集成测试,或者产品验证阶段才发现,这样导致的结果是问题不能尽早发现,因此解决问题的成本会非常高。

  B公司的一大特点是崇尚加班文化,996几乎成了程序员职业的代名词,我当时所在的Y团队成员几乎每天晚上要工作到10点,想想看,高强度的工作再加代码裸奔,软件的质量该如何保证?在我看来,这其实导致一种恶性循环,程序员在疲惫的情况下交付不可靠的软件->测试不充分->疲惫的测试人员漏测->下游或者客户发现问题->程序员加班解决问题。虽然在B公司,我在技术能力上有了很大的突破,可是在我看来,程序员几乎被绑在了公司运转的车轮上,生活空间被工作挤压,同时没有业余的时间研究新技术,学习新的软件工程方法,日复一日使用老旧的技术开发。团队里所谓的技术大牛,在我看来其实都是些聪明的程序员,他们在如何提高软件质量方面,眼界永远越不过自己的鼻尖。因此基层的程序员缺乏专业程序员的引导,他们的知识体系很难得到更新,很多人其实在如何保证软件质量方面没有任何思考,日复一日的拷贝粘贴,或者写出那些看似高明的复杂代码。为什么国内把程序员叫码农,是因为程序员几乎成了一种体力劳动者。

  我所经历的这种情况几乎成了国内技术公司普遍存在的现象。