软件测试基础
1. 软件测试与软件质量
1.1 什么是软件测试
测试(test)最早出于古拉丁字,它有“端”或“容器”的含义。在工业制造和生产 中,测试被当作一个常规的检验产品质量的生产活动。测试的含义为“以检验产品是否 满足需求为目标”。而软件测试活动包括了很重要的任务,即发现错误。
“软件测试”的经典定义是在规定条件下对程序进行操作,以发现错误,对软件质 量进行评估。
随着人们对软件工程化的重视以及软件规模的日益扩大,软件分析、设计的作用越 来越突出,而且有资料表明,60%以上的软件错误并不是程序错误,而是分析和设计错 误。因此,做好软件需求和设计阶段的测试工作就显得非常重要。这就是我们提倡的测 试概念扩大化,提倡软件全生命周期测试的理念。
1.2 什么是软件质量
2001年,软件“产品质量”国际标准ISO 9126定义的软件质蛍包括“内部质量”、 “外部质量”和“使用质量”三部分。也就是说,“软件满足规定或潜在用户需求的能力” 要从软件在内部、外部和使用中的表现来衡量。
1.3 软件测试与质量保证的区别
软件测试人员的一项重要任务是提高软件质量,但不等于说软件测试人员就是软件 质量保证人员,因为测试只是质最保证工作中的一个环节。软件质量保证和软件测试是 软件质量工程的两个不同层面的工作。
质最保证(QA):质量保证的重要工作通过预防、检査与改进来保证软件质量。QA的工作是软件生命周期的管理以及验证软件是 否满足规定的质量和用户的需求,因此主要着眼于软件开发活动中的过程、步 骤和产物,而不是对软件进行剖析找出问题或评估。
软件测试:测试虽然也与开发过程紧密相关,但关心的不是过程的活动,而是对过程的产物以及开发出的软件进行剖析。测试人员必须假设软件存在潜在的问题,测试中所作的操作是为了找出更多的问题,而不仅仅是为了验证每一件事是正确的。对测试中发现的问题的分析、 追踪与回归测试也是软件测试中的重要工作,因此软件测试是保证软件质量的一个重要环节。
2. 软件测试的目的
测试的目的,是想以最少的人力、物力和时间找出软件中潜在的各种错误和缺陷, 通过修正各种错误和缺陷提高软件质量,回避软件发布后由于潜在的软件缺陷和错误造 成的隐患所带来的商业风险。
3. 软件测试原则
- 1.所有的软件测试都应追溯到用户需求。
- 这是因为软件的目的是使用户完成预定的任务,并满足用户的需求,而软件测试所 揭示的缺陷和错误使软件达不到用户的目标,满足不了用户需求。
- 2.应当把“尽早地和不断地进行软件测试”作为软件测试者的座右铭。
- 由于软件的复杂性和抽象性,在软件生命周期各个阶段都可能产生错误,所以不应 把软件测试仅仅看作是软件开发的一个独立阶段的工作,而应当把它贯穿到软件开发的 各个阶段中。在软件开发的需求分析和设计阶段就应开始测成工作,编写相应的测试文 档。同时,坚持在软件开发的各个阶段进行技术评审与验证,这样才能在开发过程中尽 早发现和预防错误,杜绝某些缺陷和隐患,提高软件质量。只要测试在生命周期中进行 得足够早,就能够提高被测软件的质凰,这就是预防性测试的基本原则。
- 3.完全测试是不可能的,测试需要终止。
①输入量太大:
②输出结果太多:
③路径组合太多。
一个适度规模的程序,其路径组合近似天文数字,对于每一种可能的路径都执行一 次的穷举测试是不可能的。此外,测试也是有成本的,越是测试后期,为发现错误所付 出的代价就会越大,因此也要根据测试错误的概率以及软件可靠性要求,确定最佳停止 测试时冋,我们不能无限地测试下去。 - 4.测试无法显示软件潜在的缺陷。
- 进行测试是可以査找并报告发现的软件缺陷和错误,但不能保证软件的缺陷和错误 全部找到,继续进一步测试可能还会找到一些,也就是说测试只能证明软件存在错误而 不能证明软件没有错误。
- 5.充分注意测试中的群集现象 (二八定律)
- 经验表明,测试后程序中残存的错误数目与该程序中已发现的错误数目或检错率成 正比。根据这个规律,应当对错误群集的程序段进行重点测试,以提高测试投资的效益。
在所测程序段中,若发现错误数目多,则残存错误数目也比较多。这种错误群集性 现象,已为许多程序的测试实践所证实。例如,在美国IBM公司的OS/370操作系统中, 47%的错误仅与该系统的4%的程序模块有关。这种现象对测试很有用。如果发现某一程 序模块似乎比其他程序模块有更多的错误倾向,则应当花费较多的时间和代价测试这个 程序模块。 - 6.程序员应避免检査自己的程序。
- 基于心理因素,人们认为揭露自己程序中的问题总不是一件愉快的事,不愿否认自 己的工作;由于思维定势,人们难于发现自己的错误。因此,为达到测试目的,应由客 观、公正、严格的独立的测试部门或者独立的第三方测试机构进行测试。
- 7.尽量避免测试的随意性。
- 应该从工程的角度去理解软件测试,它是有组织、有计划、有步骤的活动。
4.软件测试对象
根据软件定义,软件包括程序、数据和文档,所以软件测试并不仅仅是程序测试。 软件测试应贯穿于整个软件生命周期中。在整个软件生命周期中,各阶段有不同的测试 对象,形成了不同开发阶段的不同类型的测试。需求分析、概要设计、详细设计以及程 序编码等各阶段所得到的文档,包括需求规格说明、概要设计规格说明、详细设计规格 说明以及源程序,都应成为“软件测试”的对象。
为了把握各个环节的正确性,人们需要进行各种验证和确认(verification & validation)工作。
验证(verification)是保证软件正确实现特定功能的一系列活动和过程,目的是保 证软件生命周期中的每一个阶段的成果满足上一个阶段所设定的目标。
确认(validation)是保证软件满足用户需求的一系列的活动和过程,目的是在软件 开发完成后保证软件与用户需求相符合。
验证与确认都属于软件测试,它包括对软件分析、设计以及程序的验证和确认。
5.软件测试分类
5.1 按照开发阶段划分
按照开发阶段划分软件测试可分为:单元测试、集成测试、系统测试、确认测试和 验收测试
• 单元测试。
单元测试又称模块测试,是针对软件设计的最小单位——程序模块进行正确性检验 的测试工作。其目的在于检査每个程序单元能否正确实现详细设计说明中的模块功能、 性能、接口和设计约束等要求,发现各模块内部可能存在的各种错误。单元测试需要从 程序的内部结构出发设计测试用例.多个模块可以平行地独立进行单元测试。
• 集成测试。
集成测试也叫做组装测试。通常在单元测试的基础上,将所有的程序模块进行有序 的、递增的测试。集成测试是检验程序单元或部件的接口关系,逐步集成为符合概要设 计要求的程序部件或整个系统。
软件集成的过程是一个持续的过程,会形成很多个临时版本,在不断的集成过程中, 功能集成的穏定性是真正的挑战。在每个版本提交时,都需要进行冒烟测试,即对程序 主要功能进行验证。冒烟测试也叫版本验证测试、提交测试。
•确认测试。
确认测试是通过检验和提供客观证据,证实软件是否满足特定预期用途的需求。确 认测试是检测与证实软件是否满足软件需求说明书中规定的要求。
• 系统测试。
系统测试是为验证和确认系统是否达到其原始目标,而对集成的硬件和软件系统进 行的测试。系统测试是在真实或模拟系统运行的环境下,检査完整的程序系统能否和系 统(包括硬件、外设、网络和系统软件、支持平台等)正确配置、连接,并满足用户需求。
• 验收测试。
按照项目任务书或合同、供需双方约定的验收依据文档进行的对整个系统的测试与 评审,决定是否接收或拒收系统。
5.2 按照测试实施组织划分
按照测试实施组织划分,软件测试可分为开发方测试、用户测试(卩测试)、第三方 测试。
•开发方测试。
通常也叫“验证测试”或“α测试”。开发方通过检测和提供客观证据,证实软件的 实现是否满足规定的需求。验证测试是在软件开发环境下,由开发者检测与证实软件的 实现是否满足软件设计说明或软件需求说明的要求。主要是指在软件开发完成以后,.开 发方对要提交的软件进行全面的自我检査与验证,可以和软件的“系统测试"一并进行。
•用户测试。
在用户的应用环境下,用户通过运行和使用软件,检测与核实软件实现是否符合自 己预期的要求。通常情况用户测试不是指用户的“验收测试",而是指用户的使用性测试, 由用户找出软件的应用过程中发现的软件的缺陷与问题,并对使用质量进行评价。
β测试通常被看成是一种"用户测试" β测试主要是把软件产品有计划地免费分发 到目标市场,让用户大量使用,并评价、检査软件。通过用户各种方式的大量使用,来 发现软件存在的问题与错误,把信息反馈给开发者修改。|3测试中厂商获取的信息,可 以有助于软件产品的成功发布。
•第三方测试。
介于软件开发方和用户方之间的测试组织的测试。第三方测试也称为独立测试。软 件质量工程强调开展独立验证和确认(IV&V)活动。IV&V是由在技术、管理和财务上 与开发组织具有规定程度独立的组织执行验证和确认过程。软件第三方测试也就是由在 技术、管理和财务上与开发方和用户方相对独立的组织进行的软件测试。一般情况下是 在模拟用户真实应用环境下,进行软件确认测试。
5.3 按照测试技术划分
按照测试技术划分:白盒测试、黑盒测试、灰盒测试。
也可划分为静态测试和动态测试。
-
静态测试是指不运行程序,通过人工对程序和文档进行分析与检査:静态测试技 术又称为静态分析技术,静态测试实际上是对软件中的需求说明书、设计说明书、程序 源代码等进行非运行的检査,静态测试包括:走查、符号执行、需求确认等。
-
动态测试 是指通过人工或使用工具运行程序进行检査、分析程序的执行状态和程序的外部表现。
-
白盒测试
通过对程序内部结构的分析、检测来寻找问题。白盒测试可以把程序看成装在一个 透明的白盒子里,也就是清楚了解程序结构和处理过程,检查是否所有的结构及路径都 是正确的,检査软件内部动作是否按照设计说明的规定正常进行。白盒测试又称结构测试。 -
黑盒测试(功能测试)
通过软件的外部表现来发现其缺陷和错误。黑盒测试法把测试对象看成一个黑盒 子,完全不考虑程序内部结构和处理过程。黑盒测试是在程序界面处进行测试,它只是 检査样序是否按照需求规格说明书的规定正常实现。 -
灰盒测试
介于白盒测试与黑盒测试之间的测试。灰盒测试关注输出对于输入的正确性;同时 也关注内部表现,但这种关注不像白盒测试那样详细、完整,只是通过一些表征性的现 象、事件、标志来判断内部的运行状态。
灰盒测试结合了白盒测试和黑盒测试的要素。它考虑了用户端、特定的系统知识和 操作环境。它在系统组件的协同性环境中评价应用软件的设计。
6.软件测试过程模型
6.1 V模型
V模型是最具有代表意义的测试模型,如上图V模型示意图
V模型最早是由Paul Rook 在20世纪80年代后期提出的,V模型在英国国家计算中心文献中发布,旨在改进软件 开发的效率和效果。
V模型是软件开发瀑布模型的变种,它反映了测试活动 与分析和设计的关系,从左到右,描述了基本的开发过程和测试行为,非常明确地标明 了测试过程中存在的不同级别,并且清楚地描述了这些测试阶段和开发过程期间各阶段 的对应关系,如模型图中所示,图中的箭头代表了时间方向,左边下降的是 开发过程各阶段,与此相对应的是右边上升的部分,即各测试过程的各个阶段。
V模型优点:
- 1.V模型的软件测试策略既包括低层测试又包括了高层测试,低层测试是为了源代码 的正确性,高层测试是为了使整个系统满足用户的需求。
- 2.V模型指出,单元和集成测试是验证的程序设计,开发人员和测试组应检测程序的 执行是否满足软件设计的要求;系统测试应当验证系统设计,检测系统功能、性能的质 量特性是否达到系统设计的指标;由测试人员和用户进行软件的确认测试和验收测试, 追溯软件需求说明书进行测试,以确定软件的实现是否满足用户需求或合同的要求。
- V模型缺点:
- V模型存在一定的局限性,它仅仅把测试过程作为在需求分析、概要设计、详细设 计及编码之后的一个阶段。容易使人理解为测试是软件开发的最后的一个阶段,主要是针 对程序进行测试寻找错误,而需求分析阶段隐藏的问题一直到后期的验收测试才被发现。
6.2 W模型
它强调:测试伴随着整个软件开发周期,而且测试的对象不仅仅 是程序,需求、功能和设计同样要测试。这样,只要相应的开发活动完成,我们就可以 开始执行测试,可以说,测试与开发是同步进行的,从而有利于尽早地发现问题。以需 求为例,需求分析一完成,我们就可以对需求进行测试,而不是等到最后才进行针对需 求的验收测试。
优点:
如果测试文档能尽早提交,那么就有了更多的检査和检阅的时间,这些文档还可用 于评估开发文档。另外还有一个很大的益处是,测试者可以在项目中尽可能早地面对规格说明书的挑战。这意味着测试不仅仅是评定软件的质堡,测试还可以尽可能早地找出 缺陷所在,从而帮助改进项目内部的质量。参与前期工作的测试者可以预先估计问题和 难度,这将可以显著地减少总体测试时间,加快项目进度。
缺点:
W模型也是有局限性的。W模型和V模型都把软件的开发视为需求、设计、编码 等一系列串行的活动。同样的,软件开发和测试保持一种线性的前后关系,需要有严格 的指令表示上一阶段完全结束,才可正式开始下一个阶段。这样就无法支持迭代、自发 性以及变更调整。对于当前很多文档需要事后补充,或者根本没有文档的做法下(这已 成为一种开发的文化),开发人员和测试人员都面临同样的困惑。
6.3 H模型
概括地说,H模型掲示了:
- 软件测试不仅仅指测试的执行,还包括很多其他的活动。
- 软件测试是一个独立的流程,贯穿产品整个生命周期,与其他流程并发地进行。
- 软件测试要尽早准备,尽早执行。
- 软件测试是根据被测物的不同而分层次进行的。不同层次的测试活动可以是按 照某个次序先后进行的,但也可能是反复的。
在H模型中,软件测试模型是一个独立的流程,贯穿于整个产品周期,与其他流程 并发地进行。当某个测试时冋点就绪时,软件测试即从测试准备阶段进入测试执行阶段。
6.4 其他模型
6.4.1 X模型 、前置测试模型
6.5 测试模型的使用
前面我们介绍了几种典型的测试模型,应该说这些模型对指导测试工作的进行具有 重要的意义,但任何模型都不是完美的。我们应该尽可能地去应用模型中对项目有实用 价值的方面,但不强行地为使用模型而使用模型,否则也没有实际意义。
在这些模型中,V模型强调了在整个软件项目开发中需要经历的若干个测试级别, 而且每一个级别都与一个开发级别相对应,但它忽略了测试的对象不应该仅仅包括程序, 或者说它没有明确地指出应该对软件的需求、设计进行测试,而这一点在W模型中得到 了补充。W模型强调了测试计划等工作的先行和对系统需求和系统设计的测试,但W 模型和V模型一样也没有专门针对软件测试的流程予以说明,因为事实上,随着软件质 量要求越来越为大家所重视,软件测试也逐步发展成为一个独立于软件开发部的组织, 就每一个软件测试的细节而言,它都有一个独立的操作流程。
因此,在实际的工作中,我们要灵活地运用各种模型的优点,在W模型的框架下, 运用H模型的思想进行独立地测试,并同时将测试和开发紧密结合,寻找恰当的就绪点 开始测试并反复迭代测试,最终保证按期完成预定目标。
7. 软件生命周期测试策略
7.1 软件开发与软件测试
软件开发过程是一个自顶向下,逐步细化的过程。首先,在软件计划阶段定义了软 件的作用域,然后进行软件需求分析,建立软件的数据域、功能和性能需求、约束及一 些有效性准则。接着进入软件开发,进行软件设计,把设计用某种程序设计语言转换成 程序代码。而测试过程则是依照相反的顺序安排自底向上,逐步集成的过程。低一级测 试为上一级测试准备条件。当然不排除两者平行地进行测试
7.2 软件测试策略
测试过程按4个步骤进行,即单元测试、集成(组装)测试、确认测试和系统测试。
1.测试信息流
- 软件配置:包括软件需求规格说明、软件设计规格说明、源代码等。
- 测试配置:包括测试计划、测试用例、测试驱动程序等。实际上,在整个软件工程 中,测试配置只是软件配置的一个子集。
- 测试工具:为提高软件测试效率,可使用测试工具支持测试工作,其作用就是为测试的实施提供某种服务,以减轻测试任务中的手工劳动。例如,测试数据自动生成程序、静态分析程序、动态分析程序、测试结果分析程序以及驱动测试的测试数据库等。
测试之后,要对所有测试结果进行分析,即将实测的结果与预期的结果进行比较。 如果发现出错的数据,就意味着软件有错误,就需要开始排错(调试)。即对已经发现的 错误进行错误定位和确定出错性质,并改正这些错误,同时修改相关的文档。修正后的 文档一般都要经过再次测试,直到通过测试为止。
2.分析设计阶段
分析设计阶段的测试工作是评审与测试相结合的过程,主要包括需求说明书评测、 概要设计说明书评测、详细设计说明书评测以及软件编码规范评测等。
- 需求说明书评测
- 需求说明书评测作为需求分析阶段工作的复査手段,应该对功能的正确性、完整性 和清晰性,以及其他需求给予评测。
- 概要设计说明书评测
- 软件设计的最终目标是要取得最佳方案。“最佳”是指在所有候选方案中,就节省 开发费用,降低资源消耗,缩短开发时间的条件,选择能够赢得较高的生产率、较高的 可靠性和可维护性的方案。在整个设计的过程中,各个时期的设计结果需要经过一系列 设计质量的评测,以便及时发现和解决在软件设计中出现的问题,防止把问题遗留到开 发的后期阶段,造成后患。
- 详细设计说明书评测
- 详细设计说明书的评测标准和评测内容与概要设计说明书基本相同
- 软件编码规范评测
- 程序实际上也是一种供人阅读的文章,有一个文章的风格问题。程序良好的风格表 现在源程序文档化、数据说明的方法、语句结构和输入/输出方法这四个方面,软件编码 规范评测也是围绕这四个方面展开。
3.开发阶段
- 单元测试的内容。
在进行单元测试时,测试者需要依据详细设计说明书和源程序淸单,了解该模块的 I/O条件和模块的逻辑结构,主要釆用白盒测试的测试用例,辅之以黑盒测试的测试用 例,使之对任何合理的输入和不合理的输入,都能鉴别和响应。这要求对所有的局部的 和全局的数据结构、外部接口和程序代码的关键部分,都要进行桌面检査和严格的代码 审査。
在单元测试中进行的测试工作如图所示,需要在五个方面对所测模块进行检査。
①模块接口测试
在单元测试的开始,应对通过所测模块的數据流进行测试。如果数据不能正确地输 入和输出,就谈不上进行其他测试。
调用 所测模块时的输入参数与模块的形式参数在个数、属性、顺序上是否匹配
②局部数据结构测试。 模块的局部数据结构是最常见的错误来源,应设计测试用例以检査以下各种错误:
不正确或不一致的数据类型说明;使用尚未赋值或尚未初始化的变量:错误的初始值或
错误的缺省值:变量名拼写错或书写错;不一致的数据类型。可能的话,除局部数据之 外的全局数据对模块的影响也需要査淸.
③路径测试。 常见的不正确计算有:运算的优先次序不正确或误解了运算的优先次序:运算的方
式错,即运算的对象彼此在类型上不相容;算法错;初始化不正确;运算精度不够;表 达式的符号表示不正确。
④错误处理测试。 比较完善的模块设计要求能预见出错的条件,并设置适当的出错处理,以便在一旦
程序出错时,能对出错程序重做安排,保证其逻辑上的正确性。这种出错处理也应当是
模块功能的一部分。若出现下列情况之一,则表明模块的错误处理功能包含有错误或缺
陷:出错的描述难以理解:出错的描述不足以对错误定位,不足以确定出借的原因;显
示的错误与实际的错误不符;对错误条件的处理不正确:在对错误进行处理之前,错误 条件己经引起系统的干预等。
⑤边界测试。 在边界上出现错误是常见的。例如,在一段程序内有一个n次循环,当到达第n次
重复时就可能会出错。另外,在取最大值或最小值时也容易出错。因此,要特别注意数
据流、控制流中刚好等于、大于或小于确定的比较值时出错的可能性。对这些地方要仔 细地选择测试用例,认真加以测试。
模块测试针对的程序规模较小,易于査错;发现错误后容易确定错误的位置, 易于排错,同时多个模块可以并行测试。做好模块测试可为后续的测试打下良好的基础。
模块并不是一个独立的程序,在考虑测试模块时,同时要考虑它和外界的联系,用 一些辅助模块去模拟与所测模块相联系的其他模块。这些辅助模块分为两种:
- 驱动模块(driver) ——相当于所测模块的主程序。它接收测试数据,把这些数据传 送给所测模块,最后再输出实测结果。
- 桩模块(stub)——也叫做存根模块。用以代替所测模块调用的子模块。桩模块可
以做少量的数据操作,不需要把子模块所有功能都带进来,但不允许什么事情也不做。
所测模块、与它相关的驱动模块及桩模块共同构成了一个“测试环境”
- 集成测试的内容
通常,在单元测试的基础上,需要将所有模块按照概要设计说明书和详细设计说明书的要求进行组装。
组装时需要考虑的问题。
①在把各个模块连接起来的时候,穿越模块接口的数据是否会丢失:
②一个模块的功能是否会对另一个模块的功能产生不利的影响;
③各个子功能组合起来,能否达到预期要求的父功能:
④全局数据结构是否有问题:
⑤单个模块的误差累积起来,是否会放大,以至达到不能接受的程度。
模块组装成为系统的方式
模块组装成为系统的方式有两种:一次性组装方式和增殖式组装方式。
①一次性组装方式(big bang).
使用这种方式,首先对每个模块分 别进行模块测试,再把所有模块组装在一起进行测试,最终得到要求的软件系统。
但是由于程序中不可避免地存在涉及模块间接口、全局数据结构方面的问题, 所以一次试运行成功的可能性并不很大。其结果是,发现有错误,却茫然找不到原因。 査错和改错都会遇到困难。
②增殖式组装方式。
这种组装方式又称渐增式组装,是首先对一个个模块进行模块测试,然后将这些模 块逐步组装成较大的系统,在组装的过程中边连接边测试,以发现连接过程中产生的问 题。最后通过增殖逐步组装成为要求的软件系统。
(1)自顶向下的增殖方式。
自顶向下增殖方式的缺点是需要建立桩模块,能够较早地发现主要控制方面的问题
(2)自底向上的增殖方式。
缺点是“程序一直未能作为一个实体存在,直到燉后一个模块 加上去后才形成一个实体”。由于涉及到复杂算法和其正输入瀚出的模块最先得到组装和测试,可以把最 容易出问题的部分在早期解决。
(3)混合增殖式测试。