`
softstone
  • 浏览: 477750 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

为什么要进行烦人的单元测试?

阅读更多

为什么要进行烦人的单元测试?

IPL
(本文转载自软件工程专家网www.21cmm.com

摘要

  这篇文章主要阐述这样一个问题:为什么要进行烦人的单元测试?那些刚刚接触完全测试概念的开发人员常常遇到这个问题。我们这里将采用"反调论证"的方法来回答这个问题, 先提出一些反对单元测试的普遍论点, 然后我们会证明这些论点是站不住脚的。那些公开发表的文章和数据充分证实了单元测试的有效性。

  IPL是一个独立的软件开发机构,成立于1979年,基地设在Bath。IPL在1988年通过了ISO9001认证,并在1991年通过TickIT认证。IPL开发并提供AdaTEST和Cantata等软件验证产品。AdaTEST和Cantata的开发遵循了这些标准的要求。

简介

  在使新的产品和业务的开发过程工业化的尝试中,软件的质量和可靠性常常被看作是薄弱环节。

  在最近的十年里,随着越来越多的人在开发过程中采用了设计方法论和使用CASE工具,软件质量和可靠性的问题越来越受到重视。大多数软件设计人员都接受了这方面的培训,并且在这些正规的软件设计方法的使用中取得了很多经验。

  但不幸的是,软件测试并没有得到同样的重视。很多使用这些软件设计方法的开发活动并没有使软件质量和可靠性得到控制。修改最初的软件开发活动遗留的Bug一般要在软件维护费用中占到50%的比例,这是不正常的,这些Bug应该在有效的软件测试过程中被排除掉。

  这篇文章主要阐述这样一个问题:为什么要进行烦人的单元测试?那些刚刚接触完全测试概念的开发人员常常遇到这个问题。我们这里将采用"反调论证"的方法来回答这个问题,先列出一些反对单元测试的普遍论点,然后我们会证明这些论点是站不住脚的。那些公开发表的文章和数据充分证实了单元测试的有效性。

什么是单元测试

  单元测试是在软件开发过程中要进行的最低级别的测试活动,在单元测试活动中,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。

  在一种传统的结构化编程语言中,比如C,要进行测试的单元一般是函数或子过程。在象C++这样的面向对象的语言中, 要进行测试的基本单元是类。对Ada语言来说,开发人员可以选择是在独立的过程和函数,还是在Ada包的级别上进行单元测试。单元测试的原则同样被扩展到第四代语言(4GL)的开发中,在这里基本单元被典型地划分为一个菜单或显示界面。

  单元测试不仅仅是作为无错编码一种辅助手段在一次性的开发过程中使用,单元测试必须是可重复的,无论是在软件修改,或是移植到新的运行环境的过程中。因此,所有的测试都必须在整个软件系统的生命周期中进行维护。

  经常与单元测试联系起来的另外一些开发活动包括代码走读(Code review),静态分析(Static analysis)和动态分析(Dynamic analysis)。静态分析就是对软件的源代码进行研读,查找错误或收集一些度量数据,并不需要对代码进行编译和执行。动态分析就是通过观察软件运行时的动作,来提供执行跟踪,时间分析,以及测试覆盖度方面的信息。

一些流行的误解

  在明确了什么是单元测试以后,我们可以进行"反调论证"了。在下面的章节里,我们列出了一些反对单元测试的普遍的论点。然后用充分的理由来证明这些论点是不足取的。

它浪费了太多的时间

  一旦编码完成,开发人员总是会迫切希望进行软件的集成工作,这样他们就能够看到实际的系统开始启动工作了。 这在外表上看来是一项明显的进步,而象单元测试这样的活动也许会被看作是通往这个阶段点的道路上的障碍, 推迟了对整个系统进行联调这种真正有意思的工作启动的时间。

  在这种开发步骤中,真实意义上的进步被外表上的进步取代了。系统能够正常工作的可能性是很小的,更多的情况是充满了各式各样的Bug。在实践中,这样一种开发步骤常常会导致这样的结果:软件甚至无法运行。更进一步的结果是大量的时间将被花费在跟踪那些包含在独立单元里的简单的Bug上面,在个别情况下,这些Bug也许是琐碎和微不足道的,但是总的来说,他们会导致在软件集成为一个系统时增加额外的工期, 而且当这个系统投入使用时也无法确保它能够可靠运行。

  在实践工作中,进行了完整计划的单元测试和编写实际的代码所花费的精力大致上是相同的。一旦完成了这些单元测试工作,很多Bug将被纠正,在确信他们手头拥有稳定可靠的部件的情况下,开发人员能够进行更高效的系统集成工作。这才是真实意义上的进步,所以说完整计划下的单元测试是对时间的更高效的利用。而调试人员的不受控和散漫的工作方式只会花费更多的时间而取得很少的好处。

  使用AdaTEST和Cantata这样的支持工具可以使单元测试更加简单和有效。但这不是必须的,单元测试即使是在没有工具支持的情况下也是一项非常有意义的活动。

它仅仅是证明这些代码做了什么

  这是那些没有首先为每个单元编写一个详细的规格说明而直接跳到编码阶段的开发人员提出的一条普遍的抱怨, 当编码完成以后并且面临代码测试任务的时候,他们就阅读这些代码并找出它实际上做了什么,把他们的测试工作基于已经写好的代码的基础上。当然,他们无法证明任何事情。所有的这些测试工作能够表明的事情就是编译器工作正常。是的,他们也许能够抓住(希望能够)罕见的编译器Bug,但是他们能够做的仅仅是这些。

  如果他们首先写好一个详细的规格说明,测试能够以规格说明为基础。代码就能够针对它的规格说明,而不是针对自身进行测试。这样的测试仍然能够抓住编译器的Bug,同时也能找到更多的编码错误,甚至是一些规格说明中的错误。好的规格说明可以使测试的质量更高,所以最后的结论是高质量的测试需要高质量的规格说明。

  在实践中会出现这样的情况: 一个开发人员要面对测试一个单元时只给出单元的代码而没有规格说明这样吃力不讨好的任务。你怎样做才会有更多的收获,而不仅仅是发现编译器的Bug?第一步是理解这个单元原本要做什么, --- 不是它实际上做了什么。 比较有效的方法是倒推出一个概要的规格说明。这个过程的主要输入条件是要阅读那些程序代码和注释, 主要针对这个单元, 及调用它和被它调用的相关代码。画出流程图是非常有帮助的,你可以用手工或使用某种工具。 可以组织对这个概要规格说明的走读(Review),以确保对这个单元的说明没有基本的错误, 有了这种最小程度的代码深层说明,就可以用它来设计单元测试了。

我是个很棒的程序员, 我是不是可以不进行单元测试?

  在每个开发组织中都至少有一个这样的开发人员,他非常擅长于编程,他们开发的软件总是在第一时间就可以正常运行,因此不需要进行测试。你是否经常听到这样的借口?

  在真实世界里,每个人都会犯错误。即使某个开发人员可以抱着这种态度在很少的一些简单的程序中应付过去。 但真正的软件系统是非常复杂的。真正的软件系统不可以寄希望于没有进行广泛的测试和Bug修改过程就可以正常工作。

  编码不是一个可以一次性通过的过程。在真实世界中,软件产品必须进行维护以对操作需求的改变作出反应, 并且要对最初的开发工作遗留下来的Bug进行修改。你希望依靠那些原始作者进行修改吗? 这些制造出这些未经测试的原始代码的资深专家们还会继续在其他地方制造这样的代码。在开发人员做出修改后进行可重复的单元测试可以避免产生那些令人不快的负作用。

不管怎样, 集成测试将会抓住所有的Bug

  我们已经在前面的讨论中从一个侧面对这个问题进行了部分的阐述。这个论点不成立的原因在于规模越大的代码集成意味着复杂性就越高。如果软件的单元没有事先进行测试,开发人员很可能会花费大量的时间仅仅是为了使软件能够运行,而任何实际的测试方案都无法执行。

  一旦软件可以运行了,开发人员又要面对这样的问题: 在考虑软件全局复杂性的前提下对每个单元进行全面的测试。 这是一件非常困难的事情,甚至在创造一种单元调用的测试条件的时候,要全面的考虑单元的被调用时的各种入口参数。在软件集成阶段,对单元功能全面测试的复杂程度远远的超过独立进行的单元测试过程。

  最后的结果是测试将无法达到它所应该有的全面性。一些缺陷将被遗漏,并且很多Bug将被忽略过去。

  让我们类比一下,假设我们要清洗一台已经完全装配好的食物加工机器!无论你喷了多少水和清洁剂,一些食物的小碎片还是会粘在机器的死角位置,只有任其腐烂并等待以后再想办法。但我们换个角度想想,如果这台机器是拆开的, 这些死角也许就不存在或者更容易接触到了,并且每一部分都可以毫不费力的进行清洗。

它的成本效率不高

  一个特定的开发组织或软件应用系统的测试水平取决于对那些未发现的Bug的潜在后果的重视程度。这种后果的严重程度可以从一个Bug引起的小小的不便到发生多次的死机的情况。这种后果可能常常会被软件的开发人员所忽视(但是用户可不会这样),这种情况会长期的损害这些向用户提交带有Bug的软件的开发组织的信誉,并且会导致对未来的市场产生负面的影响。相反地,一个可靠的软件系统的良好的声誉将有助于一个开发组织获取未来的市场。

  很多研究成果表明,无论什么时候作出修改都要进行完整的回归测试,在生命周期中尽早地对软件产品进行测试将使效率和质量得到最好的保证。Bug发现的越晚,修改它所需的费用就越高,因此从经济角度来看, 应该尽可能早的查找和修改Bug。在修改费用变的过高之前,单元测试是一个在早期抓住Bug的机会。

  相比后阶段的测试,单元测试的创建更简单,维护更容易,并且可以更方便的进行重复。从全程的费用来考虑, 相比起那些复杂且旷日持久的集成测试,或是不稳定的软件系统来说,单元测试所需的费用是很低的。

一些图表

  这些图表摘自<<实用软件度量>>(Capers Jones,McGraw-Hill 1991),它列出了准备测试,执行测试,和修改缺陷所花费的时间(以一个功能点为基准),这些数据显示单元测试的成本效率大约是集成测试的两倍 系统测试的三倍(参见条形图)。


  (术语域测试(Field test)意思是在软件投入使用以后,针对某个领域所作的所有测试活动)

  这个图表并不表示开发人员不应该进行后阶段的测试活动,这次测试活动仍然是必须的。它的真正意思是尽可能早的排除尽可能多的Bug可以减少后阶段测试的费用。

  其他的一些图表显示高达50%的维护工作量被花在那些总是会有的Bug的修改上面。如果这些Bug在开发阶段被排除掉的话,这些工作量就可以节省下来。当考虑到软件维护费用可能会比最初的开发费用高出数倍的时候,这种潜在的对50%软件维护费用的节省将对整个软件生命周期费用产生重大的影响。

结论

  经验表明一个尽责的单元测试方法将会在软件开发的某个阶段发现很多的Bug,并且修改它们的成本也很低。在软件开发的后期阶段,Bug的发现并修改将会变得更加困难,并要消耗大量的时间和开发费用。无论什么时候作出修改都要进行完整的回归测试,在生命周期中尽早地对软件产品进行测试将使效率和质量得到最好的保证。 在提供了经过测试的单元的情况下,系统集成过程将会大大地简化。开发人员可以将精力集中在单元之间的交互作用和全局的功能实现上,而不是陷入充满很多Bug的单元之中不能自拔。

  使测试工作的效力发挥到最大化的关键在于选择正确的测试策略,这其中包含了完全的单元测试的概念,以及对测试过程的良好的管理,还有适当地使用象AdaTEST和Cantata这样的工具来支持测试过程。这些活动可以产生这样的结果:在花费更低的开发费用的情况下得到更稳定的软件。更进一步的好处是简化了维护过程并降低了生命周期的费用。有效的单元测试是推行全局质量文化的一部分,而这种质量文化将会为软件开发者带来无限的商机。

分享到:
评论

相关推荐

    为什么要进行烦人的单元测试?

    为什么要进行烦人的单元测试?软件测试摘要这篇文章主要阐述这样一个问题:为什么要进行烦人的单元测试?那些刚刚接触完全测试概念的开发人员常常遇到这个问题。我们这里将采用"反调论证"的方法来回答这个问题,先提出...

    为什么要进行单元测试?[1]

    [1]软件测试摘要这篇文章主要阐述这样一个问题:为什么要进行烦人的单元测试?那些刚刚接触完全测试概念的开发人员常常遇到这个问题。我们这里将采用"反调论证"的方法来回答这个问题,先提出一些反对单元测试的普遍...

    人教版小学六年级英语下册unit2 what's the matter, mike单元测试卷1带答案.doc

    通过这个单元测试卷,教师可以全面评估学生对日常生活中常见健康状况和情绪表达的英语词汇及句型的理解和应用能力,同时也能锻炼他们的听力技能。学生在完成这个测试后,应该能更熟练地运用这些词汇和表达来描述自己...

    部编版道德与法治三年级上册第二单元测试卷.docx

    这份文档是针对部编版小学三年级上册道德与法治课程的第二单元测试卷,主要考察学生对于学校生活、班级规则、个人责任、义务教育权利以及尊重老师等基础道德和社会规范的理解。以下是根据试卷内容提炼出的相关知识点...

    七年级语文上册 第1单元测试题 新人教版 试题.doc

    总结来说,这份七年级语文上册第1单元的测试题涵盖了语文基础知识、语境理解、文章分析、语病辨析、古诗词填空以及主题理解等多个方面的知识点,旨在检验学生对汉语语言的综合掌握情况,同时也包含了对经典文学作品...

    河北省唐山市七年级道德与法治上册 第三单元 师长情谊单元综合测试题(无答案) 新人教版(通用).doc

    这篇文档主要围绕着师生情谊和家庭关系展开,是一份针对七年级学生的道德与法治单元测试题。测试题涵盖了对教师角色的理解、师生关系的处理、个人情感与学业的关系以及家庭亲情的重要性等多个方面。 1. **教师的...

    三年级下册道德与法治试题 - 第四单元测试卷 部编版(含答案).doc

    生活中确实处处有规则,这些规则是为了维护社会秩序,保障人们的权益,而不是为了烦人。我们应该遵守规则,让生活更有序。故答案为:×19.李小明侵犯了爸爸的通信隐私权,这是不尊重他人的表现,也是违法行为。故...

    知识领域+技术关键词+烦人的代码

    - **测试**:单元测试和集成测试是确保代码质量的重要手段,可能使用JUnit、Mockito等工具进行测试。 - **部署与运维**:项目上线可能涉及Tomcat服务器配置、负载均衡、数据库优化、性能监控等运维知识。 以上是对...

    junit-drools:JUnit + JBoss Drools集成

    摘自的Drools单元测试示例-这不是我们要如何编写单元测试的方法: public class ValidationTest { static StatelessKnowledgeSession session; @BeforeClass public static void setUpClass() throws Exception {

    Web开发敏捷之道-应用Rails进行敏捷Web开发(第3版).pdf

    ·在编写应用程序的同时,用内建的单元测试、功能测试和集成测试框架来测试应用程序; ·还有,轻松又安全地部署应用程序。 《Web开发敏捷之道:应用Rails进行敏捷Web开发(第3版)》基于:Rails2,在此前版本的基础上...

    2015_2016七年级语文上册第四单元综合测试题1新版新人教版

    1. 七年级语文测试:这个标题和描述提到的是七年级语文上册第四单元的综合测试题,这是针对初中一年级学生的学习内容,涵盖了该阶段的语文基础知识。 2. 课件:标签指出这是一个课件,可能是指用于课堂教学或自主...

    Android-一款轻量级简约好用的天气App无广告无烦人的通知栏定位精准

    8. **测试与调试**:一个完整的App开发流程还包括单元测试(如JUnit和Espresso)、集成测试以及持续集成/持续部署(CI/CD)流程,以确保应用的质量和稳定性。 9. **发布与更新**:最后,将应用发布到Google Play ...

    pluto-path:从一个或多个路径中的文件创建Pluto依赖项注入模块

    特别是在进行单元测试时,我们希望一次测试一件事。 但是,当我们的一件事使用其他事物时呢? 通过注入其他通常称为协作者的东西,我们可以将模拟或伪造物传递给受测试的代码。用法简化选项'use strict'const path ...

    sure:像老板一样断言

    根据我的经验,在单元测试中,我真的只需要做一些事情然后检查结果,我相信程序员编写断言就像编写if表达式一样是很自然的。 多亏了 Haxe 宏,我们可以分析给定的表达式并为它打印一个很好的断言失败。 一个例子?...

    mimon:正在进行的电子作品Javascript个人会计应用程序

    米蒙 一个用Javascript和编写的... 进行单元测试。 用于。 ,响应式CSS以及更多用于设计UI的样式。 用于执行深度对象比较。 用于生成的UUID。 ,Google的材料图标 以选择日期。 用于格式化日期。 用于解析XML。

    HideJoin:[BUKKIT] 删除所有已知烦人的加入和留言

    5. **测试与调试**:在开发过程中,开发者会进行大量的测试以确保插件的稳定性和功能性,这可能包括单元测试、集成测试和在实际服务器环境中的测试。 6. **源代码管理**:从压缩包的文件名称"HideJoin-master"来看...

    ql-sso-admin:实习期间为Quicken Loans工程师整理的项目

    加快贷款实习项目我为Quicken Loans的工程师构建了这个项目,他们发现频繁引用微小的小数据框和/或... Jasmine中有一些单元测试。 有人要求创建一个Docker映像以在Quicken上部署项目,但是我已经通过AWS S3进行了部署。

    lombok-plugin-0.23-2018.1.zip

    10. **调试和测试**:在调试和单元测试时,由于Lombok的自动代码生成,可能需要额外的设置来确保调试和测试的正常进行。 总之,"lombok-plugin-0.23-2018.1.zip"为开发者提供了与Lombok框架交互的IDE支持,使得Java...

    整人小程序

    这需要用到调试工具和技术,如断点、日志记录和单元测试。 8. **用户体验**:虽然整人小程序主要是为了娱乐,但良好的用户体验仍然很重要。开发者需要考虑如何在恶作剧中保持一定的趣味性和可玩性,避免过于烦人或...

    tesseract 5.0.0 最新版源码

    - **测试**:单元测试和集成测试确保代码质量。 2. **OCR流程** Tesseract 5.0.0的OCR过程大致分为四个步骤: - **图像预处理**:调整图像亮度、对比度,去除噪声,转换为灰度图像。 - **文字检测(布局分析)*...

Global site tag (gtag.js) - Google Analytics