# 软件测试概述
# 软件测试产生的背景
软件生存期分为六个步骤:计划(Planning)、需求分析(Requirement Analysis)、设计(Design)、程序编写(Coding)、测试(Testing)、运行和维护(Run and Maintenance)。
# 软件质量与质量模型
重点是 ISO

# 软件测试过程模型
- V 模型
![]()
- W 模型
![]()
- H 模型
![]()
- X 模型
![]()
# 软件测试分类及流程
# 软件测试分类
# 按照测试方法分类
- 白盒测试:白盒测试又称结构测试或逻辑驱动测试,指通过对程序内部结构的分析、检测来寻找问题。
- 黑盒测试:黑盒测试又称功能测试或数据驱动测试,指通过软件的外部表现来发现缺陷和错误。
- 灰盒测试:灰盒测试介于白盒测试和黑盒测试之间,主要关注输出对于输入的正确性;同时也关注内部表现,但这种关注不像盒测试那么详细、完整,只是通过一些表征性的现象、事件、标志来判断内部的运行状态。
# 按照测试方式分类
- 静态测试:不运行被测程序本身,仅通过分析或检查源程序的语法、结构、过程、接口等来检查程序的正确性。
- 动态测试:通过运行被测程序,检查运行结果与预期结果的差异,并分析运行效率、正确性和健壮性等性能指标。
# 按照测试过程分类
- 单元测试:单元测试又称模块测试、逻辑测试或结构测试,是针对软件设计的最小单位 —— 程序模块或功能模块,进行正确性检验的测试工作。
- 集成测试:集成测试又称组装测试、综合测试或联合测试。通常在单元测试的基础上,将所有的程序模块进行有序的、递增的测试。集成测试是检验程序单元或部件的接口关系,逐步集成为符合概要设计要求的程序部件或整个系统。
- 系统测试:系统测试为验证和确认系统是否达到其原始目标,而对集成的硬件和软件系统进行的测试。
- 验收测试:验收测试又称交付测试,是软件在完成了单元测试、集成测试、系统测试之后,产品发布之前进行的软件测试活动。
# 按照测试目的分类
- 功能测试:功能测试主要针对产品需求规格说明书对软件进行测试,逐项验证软件功能是否符合要求,包括对原定功能的检验和测试软件是否有冗余功能、遗漏功能。
- 接口测试:接口测试指对各个模块进行系统联调的测试,包含程序内接口和程序外接口测试。
- 用户界面测试:用户界面测试主要检查用户界面的风格是否满足客户的要求、界面是否友好、软件是否方便易用、系统设计是否合理、界面位置是否正确等问题。
- 健壮性测试:健壮性测试侧重于对程序容错能力的测试,主要是验证程序在各种异常情况下是否能正确运行,包括数据边界测试、非法数据测试、异常中断测试等。
- 性能测试:性能测试主要测试系统的性能是否满足用户要求,即在特定的运行条件下验证系统的能力状况。
- 强度测试:强度测试是一种性能测试,强度测试总是迫使系统在异常的资源配置下运行,目的是找出因资源不足或资源争用而导致的错误
- 压力测试:压力测试是一种性能测试,指在超负荷环境中,检验程序是否能够正常运行,检验系统的稳定性。
- 负载测试:负载测试是一种性能测试,是通过测试系统在资源超负荷情况下的表现,以发现设计上的错误或验证系统的负载能力。
- 安全性测试:安全测试主要测试系统防止非法侵入的能力,例如测试系统在没有授权的内部或者外部用户对系统进行攻击或者恶意破坏时如何运行,是否能够保证数据的安全。
- 可靠性测试:可靠性测试是指在真实的或仿真的环境中,为了保证和验证软件的可靠性水平是否满足用户的要求而进行的测试,即确定软件是否满足软件规格说明书中规定的可靠性指标。
- 恢复测试:恢复测试主要测试当出现系统崩溃、硬件错误或其他灾难性问题时系统的表现情况,以及系统从故障中恢复的能力。
- 安装/卸载测试:安装测试主要检验软件是否可以正确安装,安装过程是否符合安装规程,安装文件的各项设置是否有效,安装后是否影响整个计算机系统;卸载测试是逆过程,测试软件是否被删除干净,删除后软件是否影响整个计算机系统等。
- 兼容性测试:兼容性测试主要测试软件产品在不同的平台、不同的工具软件或相同工具软件的不同版本下的兼容性,其目的是测试系统与其他软件、硬件兼容的能力。
- 文档测试:文档测试主要检查内部/外部文档的清晰性和准确性,对外部文档而言,测试工作主要针对用户的文档,以需求说明、用户手册、安装手册等为主,检验文档是否和实际应用存在差别,而且还必须考虑文档是否简单明了,相关的技术术语是否解释清楚等问题。
# 按照执行过程是否需要人工干预分类
- 手工测试:测试人员按照事先为覆盖被测软件需求而编写的测试用例,根据测试大纲中所描述的测试步骤和方法,手工地一个一个地输入执行,包括与被测软件进行交互(如输入测试数据、记录测试结果等),然后观察测试结果,看被测程序是否存在问题,或在执行过程中是否会有异常发生,属于比较原始但是必须执行的一个步骤。
- 自动测试:自动测试是将大量的重复性的测试工作交给计算机去完成,通常是使用自动测试工具来模拟手动测试步骤,执行用某种程序设计语言编写的过程(全自动测试就是指在自动测试过程中,不需要人工干预,由程序自动完成测试的全过程;半自动测试就是指在自动测试过程中,需要手动输人测试用例或选择测试路径,再由自动测试程序按照人工指定的要求完成自动测试)。
# 软件测试原则
- 尽早测试
- 全面测试
- 全过程测试
- 独立的、迭代的测试
- Pareto 原则
- 对测试出的错误一定要有一个确认的过程
- 制定严格的测试计划
- 完全测试是不可能的,测试需要终止
- 注意回归测试的关联性
- 妥善保管一切测试过程的文档
# 软件测试用例
定义:测试用例作为测试工作的指导,是软件测试必须遵守的准则,是软件测试质量稳定的根本保障。
# 测试用例设计原则
- 基于测试需求的原则:按照测试类别的不同要求设计测试用例。
- 用成熟测试用例设计方法来指导设计:在设计测试用例时,不能只凭借一些主观或直观的想法来设计测试用例,应该以些比较成熟的测试用例设计方法为指导,再加上设计人员个人的经验积累来设计测试用例,将测试设计思想与丰富的实践经验相融合才能设计出高品质的测试用例。
- 兼顾测试充分性和效率的原则:测试用例集应兼顾测试的充分性和测试的效率,测试用例的内容都应完整,具有可操作性。
- 测试执行的可再现性原则:应保证测试用例执行的可再现性。
- 足够详细、准确和清晰的步骤:即使是一个对所要测试的内容根本不了解的新手,也能准确的按照所写的测试用例完成测试。
# 测试设计说明
- 标识符:标识符是用于引用和定位测试设计说明的唯一标识。
- 被测试的特性:被测试的特性指明所有要被测试的软件特性及其组合,指明与每个特性或特性组合有关的测试设计说明。
- 方法:描述测试的总体方法,规定测试指定特性组所需的主要活动、技术和工具。
- 测试用例信息:在这部分不定义实际测试用例,主要用于描述测试用例的相关信息。
- 通过 / 失败规则:规定各测试项通过测试的标准,即描述用来判定某项特性的测试结果是通过还是失败的准则。
# 测试用例设计应避免的问题
- 把测试用例等同于测试输入数据的设计。
- 强调测试用例设计的 “越详细越好”
- 追求测试用例设计” 一步到位 “
- 将多个测试用例混在一个用例中
- 让没有测试经验的人员测试用例
# 测试用例分类
- 功能测试用例
- 性能测试用例
- 集成测试用例
- 安全性测试用例
- 用户界面测试用例
- 安装 / 反安装测试用例
# 黑盒测试
# 等价划分类
# 等价类分类
- 有效等价类:对于程序规格说明而言,由合理的、有意义的输入数据构成的集合。
- 无效等价类:对于程序规格说明而言,由不合理的、无意义的输入数据构成的集合。
# 等价类划分原则
- 在输入条件规定了取值范围或值的个数的情况下,可以确立一个有效等价类和两个无效等价类。
- 输入条件规定了输入值的集合或者规定了 "必须如何" 的条件的情况下,可确立一个有效等价类和一个无效等价类。
- 在输入条件是一个布尔量的情况下,可确定一个有效等价类和一个无效等价类。
- 在规定了输入数据的一组值(假定 n 个),并且程序要对每一个输入值分别处理的情况下,可以确认 n 个有效等价类和一个无效等价类
- 在规定了输入数据必须遵守的规则的情况下,可确立一个有效等价类(符合规则)和若干个无效等价类(从不同角度违反规则)
- 在确知已划分的等价类中各元素在程序处理中的方式不同的情况下,则应再将该等价类进一步划分为更小的等价类。
# 边界值分析法
# 边界值分析法分类
- 标准边界值测试只考虑有效数据范围内的边界值。对于一个有 n 个变量的程序,保留其中一个变量,其取值为最小值(Min)、略高于最小值(Min+)、正常值(Normal)、略低于最大值(Max-)、最大值(Max),让其余变量取正常值,标准边界值分析测试程序会产生 4n+1 个测试用例。
- 健壮边界值测试会考虑有效和无效数据范围内的边界值。因此,对于一个含有 n 个变量的程序,保留其中一个变量,其取值为,其取值为略低于最小值(Min-)、最小值 (Min)、略高于最小值(Min+)、正常值(Normal)、略低于最大值(Max-)、最大值 (Max),略高于最大值(Max+),让其余变量取正常值,健壮边界值分析测试程序会产生 6n+1 个测试用例。
# 因果图法
# 因果图的基本关系
- 恒等:若 c_1 是 1,则 e_1 也为 1,否则 e_1 为 0。
- 非(~):若 c_1 是 1,则 e_1 为 0,否则 e_1 为 1。
- 或(V):若 c_1 或 c_2 或 c_3 是 1,则 e_1 为 1,否则 e_1 为 0。
- 与(A):若 c_1 和 c_2 都是 1,则 e_1 为 1,否则 e_1 为 0。
![]()
# 因果图的约束
# 输入条件的约束有以下 4 种
- E 约束(异,Exclusive):a 和 b 中至多有一个可能为 1,即 a 和 b 不能同时为 1。
- I 约束(或,Inclusive):a、b 和 e 中至少有一个必须是 1,即 a、b、和 c 不能同时
为 0。 - O 约束(唯一,One and Only): a 和 b 必须有一个,且有且仅有 1 个为 1。
- R 约束(要求,Request):a 是 1 时,b 必须是 1,即不可能 a 是 1 时 b 是 0。
# 输出条件的约束类型
输出条件的约束只有 M 约束(Masks,强制):若结果 a 是 1,则结果 b 强制为 0

# 决策表法
# 正交测试法
# 错误推测法
# 场景法
# 白盒测试
# 动态白盒测试
# 逻辑覆盖测试法
- 语句覆盖:语句覆盖要求设计足够多的测试用例,运行被测程序,使得程序中每条语句至少被执行一次。
- 判定覆盖:判定覆盖,又称分支覆盖,要求设计足够多的测试用例,运行被测程序,使得程序中的每个判断的 "真" 和 "假" 分支都至少被执行一次。
- 条件覆盖:条件覆盖要求设计足够多的测试用例,运行被测程序,使得判定中的每个条件获得各种可能的结果,即每个条件至少有一次为真值,有一次为假值。
- 判定 —— 条件覆盖:判定 —— 条件覆盖要求设计足够多的测试用例,运行被测程序,使得被测试程序中的每个判断本身的判定结果(真/假)至少满足一次,同时,每个逻辑条件的可能值也至少被满足一次。
- 条件组合覆盖:条件组合覆盖要求设计足够多的测试用例,运行被测程序,使得被测试程序中每个判定中条件结果的所有可能组合至少执行一次。
- 路径测试:路径测试要求设计足够的测试用例,运行被测程序,覆盖程序中所有可能的路径。
# 单元测试
考 Junit
| 注解 | 说明 |
|---|---|
| @Test | 表示方法是测试方法。与 JUnit 4 的 @Test 注释不同,这个注释不声明任何属性,因为 JUnit Jupiter 中的测试扩展基于它们自己的专用注释进行操作。 |
| @ParameterizedTest | 表示方法是参数化测试。 |
| @RepeatedTest | 表示方法是重复测试的测试模板。 |
| @TestFactory | 表示方法是动态测试的测试工厂。 |
| @TestInstance | 用于为带注释的测试类配置测试实例生命周期。 |
| @TestTemplate | 表示方法是为测试用例设计的模板,根据注册提供程序返回的调用上下文的数量进行多次调用。 |
| @DisplayName | 声明测试类或测试方法的自定义显示名称。 |
| @BeforeEach | 表示在当前类中每个 @Test、@RepeatedTest、@ParameterizedTest 或 @TestFactory 方法之前执行注释的方法;类似于 JUnit 4 的 @Before。 |
| @AfterEach | 表示在当前类中的每个 @Test、@RepeatedTest、@ParameterizedTest 或 @TestFactory 方法之后,都应该执行带注释的方法;类似于 JUnit 4 的 @After。 |
| @BeforeAll | 表示应在当前类中的所有 @Test、@RepeatedTest、@ParameterizedTest 和 @TestFactory 方法之前执行带注释的方法;类似于 JUnit 4 的 @BeforeClass。 |
| @AfterAll | 表示在当前类中,所有 @Test、@RepeatedTest、@ParameterizedTest 和 @TestFactory 方法都应该执行注释的方法;类似于 JUnit 4 的 @AfterClass。 |
| @Nested | 表示带注释的类是一个嵌套的、非静态的测试类。@BeforeAll 和 @AfterAll 方法不能直接在 @Nested 测试类中使用,除非使用 “每个类” 测试实例生命周期。 |
| @Tag | 用于在类或方法级别声明过滤测试的标记;类似于 TestNG 中的测试组或 JUnit 4 中的类别。 |
| @Disabled | 用于禁用测试类或测试方法;类似于 JUnit 4 的 @Ignore。 |
| @ExtendWith | 用于注册自定义扩展。 |
| 方法名称 | 方法描述 |
|---|---|
| assertEquals | 断言传入的预期值与实际值是相等的。 |
| assertNotEquals | 断言传入的预期值与实际值是不相等的。 |
| assertArayEquals | 断言传入的预期数组与实际数组是相等的。 |
| assertNull | 断言传入的对象是为空。 |
| assertNotNull | 断言传入的对象是不为空。 |
| assertTrue | 断言条件为真。 |
| assertFalse | 断言条件为假。 |
| assertSame | 断言两个对象引用同一个对象,相当于 "=="。 |
| assertNotSame | 断言两个对象引用不同的对象,相当于 "!="。 |
| assertThat | 断言实际值是否满足指定的条件。 |
# 集成测试
# 集成测试方法
# 非增量式集成测试
# 非增量式集成测试步骤
- 对软件单元 A 进行测试。
- 对软件单元 B 进行测试。
- 对软件单元 C 和软件单元 D 进行测试。
![]()
![]()
# 非增量式集成测试的优点。
- 非增量式集成测试可以并行地测试所有的软件单元,能够加快测试工作的速度,充分利用了人力和物力资源。
- 非增量式集成测试需要用到测试用例数量较少,因此,对设计测试用例的工作量相对较小。
- 非增量式集成测试的测试方法较为简单,容易执行。
# 非增量测试的缺点
- 非增量式集成测试是将软件单元一次性集成起来,如果集成的软件单元数量较多,集成测试过程中可能会出现较多的错误,而且因为一次性集成,很难判断出现错误的位置。而且,在对某个软件单元的某处错误进行修改之后,可能会在系统的其他地方带来新的错误,这样给整个系统的修正会带来较大的难度。
- 非增量式集成测试因为是一次性集成,各个软件单元之间的接口没有进行充分的测试,因此,有可能会遗漏一些潜在的接口错误,即使在集成测试通过,这些接口可能也会存在问题。
# 非增量式集成测试的适用范围
- 适用于功能单一,所组成的软件单元不多,运行逻辑较为简单的,并且每个软件单元都经过充分的单元测试的小型软件项目。
- 适用于那些在前期已经有较为稳定的产品的项目,而且只需要修改和增加为数不多的几个软件单元。
# 增量式集成测试⭐⭐⭐
# 自顶向下集成
# 自顶向下集成测试的步骤。
- 保证所有需要集成在一起的软件单元都必须已经通过了单元测试。
- 将主控模块作为测试用驱动模块,所有与主控模块直接相连的软件单元作为测试用被调用模拟子模块。
- 根据集成的方式,深度优先或者是广度优先,逐步使用实际的软件单元替换相应的下层被调用模拟子模块,再用被调用模拟子模块代替它们的下属模块,与已经通过测试的软件单元或子系统组装成新的子系统。
- 进行回归测试(重新执行以前做过的全部或部分测试),来确定所有集成新软件单元后没有对整个系统引入新的错误。
- 从第③步开始重复执行,一直到所有的软件单元都已经集成到系统中。
# 自顶向下增量式集成测试的优点
- 在集成测试的过程当中,可以首先验证主要的控制和判断点,即主控软件单元,在功能划分合理的程序模块结构中,对于较高层次中的主控软件单元,可以首先做出测试,能够提前发现问题,以便及时对程序做出相应的修改,减少人力资源消耗。
- 选择深度优先的集成方式,可以首先实现和验证一个完整的软件功能,能够首先对逻辑输入的分支进行组装和测试,检测出潜在的错误和缺陷,验证其功能的正确性,为之后的主要分支的组装和测试提供保证。
- 能够较早的验证软件功能的可用性,给软件的开发者和软件的用户奠定了信心。在通常的情况下,几乎不用设计和开发测试用驱动程序,大大减少测试用驱动程序的开发和维护的成本。
# 自顶向下增量式集成测试的缺点
- 采用自顶向下的集成测试方法,在测试时需要给每个软件单元的下层软件单元设计开发测试用被调用模拟子模块,对于被调用模拟子模块的开发和维护成本较大。
- 当底层的软件单元发生变更时,例如,需求发生变化导致软件单元发生变化,这种变更可能会影响到整个软件中的其他软件单元,可能会需要修改整个软件系统中的多个上层软件单元,进而容易破坏之前构造的已经构造好的测试包。
- 随着自顶向下集成测试的进行,新的底层软件单元不断加入,这会让整个系统变得越来越复杂,可能会导致之后加入的底层软件单元的测试不够充分。
# 自顶向下增量式集成测试的适用范围
- 被测软件系统的结构较为清晰,控制结构较为稳定
- 被测软件系统中的高层模块接口定义较为准确,变化的可能性较小
- 被测软件系统中的低层模块接口定义还未清晰或有较大可能会因为需求发生变更等原因而发生变化
- 开发者和用户希望尽可能早的看到被测软件系统较为完整的功能
# 自底向上集成
# 自底向上集成测试的步骤
- 保证所有需要集成在一起的软件单元,都必须已经通过了单元测试。
- 从最底层的软件单元开始组装,组装成一个能够完成软件子功能的构件。
- 编写驱动程序。
- 测试集成后的构件。
- 使用实际的软件单元替换相应的驱动程序,按程序结构向上组装测试后的构件。
其中,从第③步开始重复执行,一直到所有的最顶层的软件单元都已经集成到系统中
为止。
# 自底向上增量式集成测试的优点
- 能够尽早验证底层软件单元的功能。任何一个底层软件单元通过单元测试之后,都可以开始进行集成测试。
- 在集成测试开始时,可以同时对系统层次结构中的每个分支集成测试,这样较大提高了测试的效率。
- 减少了设计开发测试用被调用模拟子模块的工作量。
- 更容易对被测系统的错误进行定位。
# 自底向上增量式集成测试的缺点
- 只有在被测系统的最顶层的最后一个软件单元组装起来之后才能看到整个系统的框架。
- 测试用驱动模块的开发和维护工作量大。
- 由于顶层的软件单元要到集成测试的最后阶段才能进行测试,所以不能及时发现高层模块设计上的错误,对于那些在整个体系结构中控制结构非常关键的产品来说,受到的影响就更大。
# 自底向上增量式集成测试的适用范围
- 底层模块接口比较稳定的软件系统
- 高层模块接口可能会存在变更比较频繁的软件系统
- 底层模块开发和单元测试工作完成较早的产品
# “三明治” 集成
# "三明治" 集成测试方法的基本步骤。
- 确定以哪一层作为运用 "三明治" 集成测试方法的分界层。
- 对分界层及其所在层下面的各个层次使用自底向上的集成测试方法。
- 对分界层上面的各个层次使用自顶向下的集成测试方法。
- 对被测系统进行整体测试。
# "三明治" 集成测试的优点
- 同时具有自顶向下集成测试和自底向上集成策略的优点。
- 通过一定集成技巧,可以减少被调用模拟子模块和驱动模块的开发。
# "三明治" 集成测试的缺点
在被集成之前,中间层不能够尽早得到充分的测试。
# "三明治" 集成测试的适用范围。
"三明治" 集成测试适用范围广泛,大多数的软件开发项目都可以应用这种集成测试
的方法。
# 系统测试
JMeter
# 验收测试
# α 测试
- 它是在开发环境下进行的(不对外发布)
- 它不需要测试用例评价软件使用质量
- 用户往往没有相关经验,可以是兼职人员,开发者或测试者坐用户旁边
- 目的主要评价软件产品的 FLURS-Function、Location、Usability、reliability、Performance、Security 即功能、局域化、可用性、可靠性、性能和技术支持.
# β 测试
软件的多个用户在一个或多个用户的实际使用环境下进行的测试。开发者通常不在测试现场,Beta 测试不能由程序员或测试员完成。
# 其他测试技术
# 功能测试
Functional testing (功能测试),又称 behavioral testing (行为测试),根据产品特性、操作描述和用户场景,测试产品的特征和可操作行为,以确定其满足设计需求。功能测试软件,用来验证应用程序或网站是否能够为目标用户正常工作。
# 回归测试
回归测试是软件开发过程质量控制措施的一个重要方面,用于验证最近对软件的更改或更新是否无意中引入了新错误或对以前的功能方面产生了负面影响。
# 性能测试
性能测试(Performance Test)就是为了发现系统性能问题或获取系统性能相关指标而进行的测试。
# 衡量指标
- 响应时间
- 服务端响应时间
- 网络响应时间
- 客户端响应时间
- 吞吐量
- 资源使用率
- 点击数
- 并发用户数
# 冒烟测试
冒烟测试是软件测试中的一项基础测试,用于快速验证系统的关键功能能是否正常运作。






