1. Key Issues in Software Testing
1.1 选择标准和充分性标准
这一节我们来关注软件测试中的一些关键问题。首先我们关注第一个问题,测试用例的选择标准和测试用例的充分性标准。
测试用例的选择标准可以告诉我们测试用例集对某个特定的目标是否足够。
而测试的充分性标准可以告诉我们测试做到什么程度,就已经足够完善,就可以终止。
注:2023 年试卷中考过
1.2 测试的目标
第二个关键问题是测试的目标,我们需要知道我们所开展的软件测试活动的目标是什么,是为了尽可能多地发现软件当中可能存在的错误,还是对软件的可靠性进行评估和度量。很显然在不同的测试目标下,我们可能采用不同的软件测试方法和软件测试策略。
1.3 错误的发现和检测
第三个关键问题是错误的发现和检测。按照传统的定义,软件测试可以被看作是一个为了发现软件当中可能存在的错误而执行软件的过程,所以我们需要去尽可能多的检测错误,这样就可以使得遗留在软件当中的未被发现的错误尽可能的少。在这种诉求下,我们可以认为一个成功的测试用例,应该是一个能够尽可能多的检测错误的测试用例,而如果测试用例不能检测错误,而如果一条测试用例不能够检测错误,我们就需要对它的质量产生怀疑。
1.4 测试预言
在执行测试用例的过程中,我们会遇到一个关键的问题,那就是测试预言问题(Test Oracle)。所谓测试预言是指测试用例的预期输出,我们需要能够预先知道一条测试用例的预期输出,只有这样才能够将预期的输出与软件的实际输出进行比对,进而根据这个预期输出来判断测试用例的运行结果是通过还是失败。但是很遗憾,在很多情况下,想要自动化的得到测试用例的预期输出是比较困难的。
1.5 测试的局限性
我们还必须明白软件测试是有局限性的,迪杰卡斯特拉曾经说过一句话:"program testing can be used to show the presence of bugs, but never to show their absence."。也就是说测试仅仅能够证明错误的存在,而不能用来证明软件中不存在遗留的未被发现的错误。这是由于在实际的软件测试过程当中,由于各种条件的限制,进行完全的测试是不可能的,也就是说我们在测试时必然会面临遗漏错误的风险。
1.6 不可达路径
在进行软件测试时,我们希望程序所有可能的行为,所有可能的语句,所有可能的分支,所有可能的路径都能被我们所测试。但事实上程序当中可能会存在一些不可达的语句不可达的分支,不可达的路径。这里所谓的不可达是指在任意可能的输入下,一些程序结构都不会被执行到。
1.7 软件的可测试性
软件的可测试性一般来说有两个方面的含义,我们一方面要关注被测试软件是否能够容易地达到测试充分性标准,满足测试终止条件。另一方面我们关注被测软件是否能够容易地被找到错误,显然软件的可测试性越强,那么我们在投入一定的资源进行软件测试后,软件当中可能遗留的未被发现的错误就会越少,软件的质量就会越高。
2. Test Levels
这一节我们来关注软件测试活动的分级和分类,相关的素材来自于软件工程知识体系结构导论,swebok 3.0 版本。
2.1 根据测试对象分级
首先我们根据测试对象的不同,对软件测试活动进行分级,如果大家学习过软件工程,一定会对瀑布模型有所了解。在瀑布模型中,软件的开发流程被分为这样几个阶段,首先获得需求,然后对其进行规约,接下来进行架构的设计,然后进行编码,实现从而获得程序的源代码,接下来进行程序的维护和测试。
在这样一个过程中,在需求和规约阶段,我们会明确整个系统的需求,在架构设计阶段,我们会了解整个系统不同模块之间是以什么样的方式配合工作的,而在编码实现阶段,我们会得到每一个模块的具体源代码,在软件测试中根据测试对象的不同,我们可以将测试活动分为单元测试、集成测试和系统测试。
- 单元测试是用来测试单独的软件模块的功能,所谓的模块可能是单个子程序,或者是有高度内聚的单元所组成的一个较大的组件单元;
- 集成测试用来测试软件组件之间的交互过程,经典的集成测试策略,包括自上而下的集成测试策略和自下而上的集成测试策略,具体采用什么样的集成策略,通常是由体系结构所决定的;
- 系统测试是为了测试整个软件系统的行为在进行系统测试的时候,我们一方面要关注系统的功能,另外一方面也需要关注一些非功能性的需求,例如安全性、性能、可靠性等等。
系统测试之后可以形成一个 V 字型的模型,其中单元测试与模块的编码实现活动所对应,每个模块实现之后都需要进行单元测试。集成测试与架构设计活动所对应,因为架构设计会决定我们应该采取什么样的集成测试策略。最后系统测试是为了测试整个软件系统的行为,所以和规约是对应的。
2.2 根据测试目标分级
首先来了解验收测试(Acceptance Testing),验收测试是用来检查整个系统是否满足了系统的验收准则,验收准则通常是由用户根据其对软件的需求来决定的,也就是说验收测试主要关注系统是否满足了用户的需求,所以在 V 字型模型当中,验收测试可以与需求这一环节所对应。
阿尔法测试和贝塔测试往往被认为是验收测试的一种:
- 阿尔法测试是指在软件正式发布之前,挑选一小批潜在用户来对软件进行测试
- 贝塔测试是在软件正式发布之前,挑选一大批有代表性的用户来对软件进行试用
那么它们之间的区别有一点是阿尔法测试可能会得到开发人员的指导,而贝塔测试则不会有这样的指导。
安装测试也是验收测试的一种,一般有两个方面的含义:
- 一方面安装测试活动可以对安装程序来进行测试和验证;
- 另一方面我们会关注软件在安装到目标环境之后,在给定的软硬件配置下是否能够正常工作。
配置测试用来检查软件在不同的配置下是否能够正常工作。一般来说根据具体的需求,软件往往需要工作于若干种不同的配置之下,在所有可接受的配置范围内,软件都应该能够正常的工作。
性能测试用来判断软件是否满足了指定的性能要求,同时我们还会通过性能测试来评估软件的性能特征,例如容量、响应时间等等。
类似的有一个概念是压力测试,它主要关注软件在最大设计负载之外的行为,通过压力测试可以确定负载的最大限制,并测试系统在超出允许负载之后的防御机制,性能测试和压力测试的概念有时容易被混淆,需要引起我们的关注。
接口测试,它通过模拟应用程序对 API 的调用,来验证组件是否能够通过正确的接口来提供正确的数据和正确的控制信息交换。接口测试的测试用例通常是根据程序的接口规范而生成的,也就是说这里所谓的接口通常指的是应用程序接口 API 。
那么程序与人之间的接口如何进行测试,这就需要进行所谓的用户界面与可用性测试,在用户界面与可用性测试当中,我们主要关注软件的用户界面,是否方便用户的学习和使用。
回归测试。我们以大家所熟知的敏捷开发为例,在敏捷开发的过程中会经过多次迭代,每一轮迭代中都会进行测试,当迭代进入第二轮以后所进行的测试活动就是回归测试。通俗的说回归测试就是在系统发生变化,或者是系统进行过修改和迭代之后,对软件进行选择性的重新测试,以验证此前的错误是否已被修改,有没有引入新的错误,软件是否依然符合需求等等。
3. 软件测试的常用术语
3.1 软件测试的定义
首先我们来看到底什么叫软件测试?
- 在 1979 年米尔斯将软件测试定义为了发现软件中可能存在的错误,而执行软件的过程;
- 在 webook 文档中,软件测试被定义为一个从无限的输入域上寻找有限的测试用例,并使用这些有限的测试用例来对程序的行为进行动态验证的方法;
- 在维基百科上还有另外一个定义,软件测试被定义为了判断软件是否满足特定的需求规约,而对软件进行分析评价的过程。
3.2 什么是测试用例
一般来说测试用例需要包含三个要素,分别是输入、预期输出以及其他一些要素,主要是环境要素。
特别注意,如果考试写的测试用例没有预期输出会扣一半分
那么什么是环境要素呢,来看下面这段程序和两个不同的测试用例:
我们考虑一下这段程序的执行环境,它是 16 位系统还是 32 位系统,如果是在一个 16 位的系统下面,我们输入 x
等于 1
,y
等于 65535
,预期结果会是 0
,因为会发生整数溢出。而如果是在一个 32 位的系统下,同样的输入,预期结果就应该是 65536
,不会发生整数溢出。
3.3 测试和调试
接下来有一组容易被混淆的概念,它们是测试和调试:
- 测试是一个为了发现错误而运行软件的过程,它的目标在于发现错误;
- 调试指的是我们发现了错误之后修改错误的一个过程。
3.4 软件测试技术
软件测试技术一般来说被分为黑盒测试技术和白盒测试技术。所谓的黑盒测试技术就是指在进行测试时,不需要使用源代码的信息,一般用在集成测试和系统测试等比较高级的层面。而白盒测试技术则会使用代码信息,它一般用在单元测试当中,后来人们又提出了灰盒测试的概念,所谓灰盒测试是介于白盒测试和黑盒测试之间的一种测试,灰盒测试多用于集成测试阶段,它不仅关注输出输入的正确性,同时也关注程序的内部情况。
灰盒测试不像白盒测试那样详细完整,但又比黑盒测试更多的关注程序内部的逻辑,这里我们要注意,灰盒测试并不是简单的,即使用黑盒测试又使用白盒测试,在一些比较新的分类方法当中,人们已经不再使用黑盒测试、白盒测试、灰盒测试这样的提法。比如在 swebok 文档当中,软件测试技术就被进行了更加详细的分类:
3.5 静态测试与动态测试
软件测试在传统上被定义为一个为了发现可能存在的错误而运行软件的过程,所以它一定是一个动态的过程。但是在一些新的软件测试的定义中,将很多为了评价和提升软件质量而进行的活动,也都归到了软件测试这样一个大的范畴之下,所以就出现了静态测试这一概念。
所谓的静态测试就是在对程序进行分析和质量判断的时候,不会真的去运行这段程序。
3.6 Verification 与 Validation
之后我们再关注一组概念,分别是 Verification 验证和 Validation 确认,这组概念也经常会被人们混淆。
确认和验证都和软件质量相关,但是确认主要是一个外部的过程,用户回来确认软件的质量,判断软件的功能性能是否符合用户的要求,而验证更多是一个内部的过程。开发组织内部对软件产品进行验证,看其是否符合规约相关的概念,同样也是出自于 IEEE 的相关文档。