软件测试应用技术(2) -- 软件评测师(十五)
3 基于结构的测试技术
基于结构的测试技术其实就是白盒测试技术,包括静态测试技术和动态测试技术,以及基于结构测试的一些辅助技术。
3.1 静态测试技术
静态测试是在不运行代码的情况下,通过一组质量准则或其他准则对测试项进行检查的测试。相对于动态测试而言,静态测试的成本更低,效率更高,更重要的是可以在软件生存周期的早期阶段发现软件缺陷。静态测试技术包括三类:
(1)代码检查:一般在编译和动态测试之前进行,代码检查的常见形式有如下两种:
1)代码审查:目的是检查代码和设计的移植性、代码执行标准的情况、代码逻辑表达的正确性、代码结构的合理性以及代码的可读性。
2)代码走查:有测试人员组成小组,准备一批有代表性的测试用例,集体扮演计算机的角色,沿程序的逻辑,逐步运行测试用例,查找被测软件的缺陷。
常见的代码检查项目如下:
1)检查变量的交叉引用表
2)检查标号的交叉引用表
3)检查子程序、宏、函数。
4)等价性检查
5)常量检查
6)标准检查
7)风格检查
8)比较控制流
9)选择、激活路径
10)对照程序的规格说明,详细阅读源代码,逐字逐句进行分析和思考,比较实际的代码和期望的代码,从它们的差异中发现程序的问题和错误。
11)补充文档
(2)编码规则检查:使用编码规则工具对代码进行检查,通常是通过在工具软件中选择对应的编码规则,或根据当前项目的要求来定制所需要的编码规则,然后使用工具软件依据这些选定的编码规则对被测代码进行扫描。最后阅读工具软件所给出的扫描结果报告文件,检查代码中那些违反编码规则的地方是否存在潜在风险。
(3)静态分析:提供了一种机制,可以审查代码结构、控制流和数据流,检测潜在的可移植性和可维护的问题,计算适当的软件质量测度。测试人员通过使用测试工具分析程序源代码的系统结构、数据结构、数据接口、内部控制逻辑等内部结构,生成函数调用关系图、模块控制流图、内部文件调用关系图、子程序表、宏和函数参数表等各类图形图表,可以清晰地标识整个软件系统的组成结构,使其便于阅读与理解,然后可以通过分析这些图表,检查软件是否存在缺陷。
静态分析测试分析工具提供如下的辅助分析:
1)控制流分析:常见的控制流分析方法是通过生成程序的有向控制流图来对代码进行分析。基本结构如下:
McCabe圈复杂度是目前较为常用的一种代码复杂度的衡量标准。它是对源代码中线性独立路径数的定量测量,可以用来衡量一个模块判定结构的复杂程度。圈复杂度与分支语句(if-else、switch-case等)和循环语句(for、while)的个数,以及判定复合条件的逻辑组合符成正相关。当一段代码中含有较多的分支语句,其逻辑复杂程度就会增加。圈复杂度V(G)计算公式有如下3种:
- V(G)=e-n+2
- V(G)=P+1
- V(G)=A+1
其中:e代表控制流图中的边数量;n代表控制流图中的节点数量。P代表控制流图中的判定节点数;A表示流图中的封闭区域数目。
线性无关路径是指包含一组以前没有处理的语句或条件的路径。从控制流图上来看,一条线性无关路径是至少包含一条在其他线路无关路径中从未有过的路径。程序的环路复杂度等于线性无关路径的条数,需要注意的是,基本路径集不是唯一的,对于给定的控制流图,可以得到不同的基本路径集。
2)数据流分析:数据流指的是数据对象的顺序和可能状态的抽象表示。数据值的变量存在从创建、使用到销毁的一个完整状态。数据流分析的作用是用来测试变量设置点和使用点之间的路径。这些路径也称为“定义-使用对”。对“定义-使用对”的检查能快速发现软件的定义和使用异常方面的缺陷,如下内容:
- 所使用的变量没有被定义(未定义),严重错误。
- 变量被定义,但从来没有使用(未使用),可能是编程错误。
- 变量在使用之前被定义了两次(重复定义),可能是编程错误。
3)接口分析:接口一致性的设计分析可以检查模块之间接口的一致性和模块与外部数据库之间接口的一致性。程序关于接口的静态错误分析主要检查过程与实参在类型、函数过程之间接口的一致性,因此要检查形参与实参在类型、数量、维数、顺序、使用上的一致性;检查全局变量和公共数据区在使用上的一致性。
4)表达式分析:对表达式进行分析,以发现和纠正在表达式中出现的错误。包括如下内容:
- 在表达式中不正确地使用了括号造成错误。
- 数组下标越界造成错误
- 除数为零造成错误
- 对负数开平方
- 对
求正切造成错误
- 对浮点数计算的误差进行检查
3.2 动态测试技术
基于结构的动态测试主要关注语句、分支、路径、调用等程序结构的覆盖,动态测试的关键是用例设计,基于结构的动态测试用例设计,其设计基础是建立在对软件程序的控制结构的了解上的。原则上应做到:
(1)保证一个模块中的所有独立路径至少被使用一次。
(2)对所有逻辑值均需测试true和false。
(3)在上下边界及可操作范围内运行所有循环
(4)检查内部数据结构以确保其有效性。
常见的测试用例设计方法可以分为基于控制流和数据流两类,具体情况如下:
(1)基于控制流设计测试用例:通过对程序控制流所表达出来的逻辑结构的遍历,实现对程序不同程度的覆盖,并认为当所选择的用例能达到对应程度的覆盖时,执行这些用例能够达到期望的测试效果。具体的方法有如下几条:
1)语句测试:选择足够多的测试数据,使被测试程序中每条语句都要被遍历到。
2)分支测试:程序中的每个分支都要被遍历到,哪怕这个分支上没有语句。
3)判定测试:程序中的每个判定语句的取值都要被遍历到。
4)条件覆盖:每一判定语句中每个判定条件的可能值至少满足一次。
5)分支条件测试(判定条件测试):设计足够的测试用例,使得每个判定语句的取值,以及每个判定条件的取值都能被覆盖到。
6)分支条件组合测试:要求设计足够的测试用例,使得每个判定语句中的所有判定条件的各种可能组合都至少出现一次。
7)修正条件判定测试:简称MCDC测试,要求足够的测试用例来确定各个条件能够影响到包含的判定的结果。它要求满足两个条件:
- 每一个程序模块的入口点和出口点都要考虑至少要被调用一次,每个程序的判定到所有可能的结果值要至少转换一次。
- 程序的判定被分解为通过逻辑操作符(and、or)连接的bool条件,每个条件对于判定的结果值都是独立的。
对于包含n个布尔条件的代码,MCDC测试只需要n+1个测试用例即可实现100%覆盖率。
(2)基于数据流设计测试用例:基于数据流设计用例是通过选择的“定义-使用”的覆盖率来导出测试用例集,以覆盖测试项中变量定义和使用之间的路径。不同的数据流覆盖准则要求执行不同“定义-使用”对和子路径。“定义”可能给变量赋了新的值(有时定义将变量保存与之前相同的值)。“使用”是变量出现,但不是赋新的值。“使用”可以进一步划分为:
1)“P-USE”(谓词使用):是指使用变量来确定判定条件(谓词)的结果,例如while循环、if-else等判定中。
2)“ C-use”(计算使用):是指一个变量作为其他变量定义或输出的计算输入。
基于数据流设计用例的测试覆盖项见下表:
测试覆盖项 | |
全定义测试 | 从变量定义到使用(计算使用或谓词使用)的控制流子路径 |
全计算使用测试 | 从变量定义到该定义所有计算使用的控制流子路径 |
全谓词使用测试 | 从变量定义到该定义所有谓词使用的控制流子路径 |
全使用测试 | 从每个变量定义到该定义的任一使用(包括谓词使用和计算使用)的控制流子路径。 |
全定义-使用路径测试 | 从每个变量定义到该定义的每次使用(包括谓词使用和计算使用)的控制流子路径。 |
3.3 基于结构的测试辅助技术
基于结构的测试辅助技术有很多,主要有如下三类:
(1)词法和语法分析:词法分析读入源程序的字符流,按一定的词法规则把它们组成词法记号流,供语法分析使用。语法分析的作用就是识别由词法分析给出的记号流序列是否是给定上下文无关文法的正确句子。
(2)程序插桩技术:是借助往被测程序中插入操作,来实现测试目的的方法,插入内容也称为桩模块。程序插桩技术能够按用户的要求获取程序的各种信息,如果我们想要了解一个程序在某次运行中所有可执行语句被覆盖(或称被遍历)的情况,或是每个语句的实际执行次数,最好的办法就是利用插桩技术。
(3)程序驱动技术:程序驱动是一个模拟程序,也称为驱动模块。它在测试时能传递数据给模块,而且能接收模块已处理过的数据,以使该模块运行。
3.4 基于结构测试方法的选择策略
基于结构的各种测试用例设计方案的综合选择策略如下:
(1)在测试中,应尽量先用工具对被测软件进行静态分析。利用静态分析的结果作为引导,通过代码检查和动态测试的方法对静态分析结果进行进一步的确认,能使测试工作更为有效。
(2)测试中可采取先静态后动态的组合方式。先进行静态分析、编码规则检查和代码检查等,再根据测试项目所选择的测试覆盖率要求,设计动态测试用例。
(3)覆盖率是对动态测试用例设计是否重复的监督。执行测试用例的目标仍然是检查每个用例的实测结果是否满足期望输出要求,而不是仅仅查看用例执行完之后覆盖率是否达到要求。
(4)根据被测软件的安全风险要求,应使用与之对应的覆盖率标准来衡量代码需要被多少测试用例进行充分测试。一般地,常规软件测试应达到语句、分支和判定测试均100%覆盖,对于一些高安全的软件可能需要达到MCDC测试100%覆盖。
(5)在不同的测试阶段,测试的侧重点不同。在单元测试阶段,以代码检查、编码规则检查和动态测试为主;在系统测试阶段,在使用编码规则检查和静态分析度量工具对代码进行扫描检查后,主要根据黑盒测试的结果,采取相应的白盒测试作为补充。
3.5 测试覆盖准则
测试覆盖是衡量测试用例的设计是否足够的方法,使用不同的测试技术,按照不同的覆盖强度划定了待覆盖的测试覆盖项后,通过不断地导出测试用例达到对测试覆盖项的覆盖,这样设计出来的测试用例集,我们就认为是符合要求的,执行这些测试用例就能够检出代码中可能存在的问题。
(1)ESTCA覆盖准则:ESTCA,即错误敏感测试用例分析。具体如下:
- [规则1]对于A rel B(rel可以是<、=和>)型的分支谓词,应适当地选择A与B的值,使得当测试执行到该分支语句时, A<B和A>B的情况分别出现一次。
- [规则2]对于A rel C(rel可以是“>”或是“<”,A是变量,C是常量)型的分支谓词,当rel为“<”时,应适当地选择A的值,使A=C-M。其中,M是最小单位的正数,若A和C均为整型则M=1。同样,当rel为“>”时,应适当地选择A,使A=C+M。
- [规则3]对外部输入变量赋值,使其在每一测试用例中均由不同的值和符号,并与同一组测试用例中其他变量的值和符号不一致。
(2)层次LCSAJ覆盖准则:LCSAJ,即线性代码序列与跳转。一个LCSAJ是一组顺序执行的代码,以控制流的跳转为其结束点。它的起点是程序第一行或转移语句的入口点,或是控制流可以跳达的点。几个首尾相接,且第一个LCSAJ起点为程序起点,最后一个LCSAJ终点为程序终点的LCSAJ串就组成了程序的一条路径。一条程序路径可能是由两个、三个或多个LCSAJ组成的。LCSAJ覆盖准则如下:
1)第一层是语句覆盖。
2)第二层是分支覆盖。
3)第三层是LCSAJ覆盖,亦即程序中的每一个LCSAJ都至少在测试中被经历过一次。
4)第四层是两两LCSAJ覆盖,亦即程序中的每两个首尾相连的LCSAJ组合起来都至少在测试中被遍历过一次。
........
5)第n+2层,每n个首尾相连的LCSAJ组合起来都至少在测试中被遍历过一次。
显然,层次越高,对应的覆盖就需要更多测试用例,更难以满足。
4 分层架构软件测试
4.1 分层架构软件测试概述
分层架构将软件分成若干层,每层有各自清晰的职责分工,层与层之间通过接口交互和传递信息,本层不需要直到其他层细节,上层通过对下层的接口依赖和调用组成一个完整的系统。基于分层架构应用测试可以根据每一层的特点,进行单独测试,更容易发现缺陷和错误。同时,也可以将分层架构软件看成一个有机整体,以黑盒方式进行确认测试、系统测试、验收测试。常见的分层架构如下图所示:
(1)分层架构各层的定义和作用如下:
- 表示层:也称用户界面层,负责具体业务和视图展开,如网页、App客户端等UI展示。
- 服务层: 也称为应用层,为表示层提供各种服务支持,如用户、登录、订单等服务接口管理。
- 业务逻辑层:也称领域层,提供业务规则、业务流程的具体逻辑方法实现。
- 数据层:提供数据访问和数据管理服务,如数据库、缓存、文件、搜索引擎等。
(2)分层架构的优点:
- 复用性强:按层进行拆解,可以用新的实现来替换原有层次的实现,利于二次开发。
- 利于合作开发:开发人员可以只关注整个结构中的其中某一层,便于分工合作开发。
- 分层独立:各层之间互不影响,可以独立演化发展,有利于标准化
- 维护方便:分层架构应用可以进行分离部署,方便维护和扩展。
(3)分层架构的缺点:
- 性能下降:由于分层设计要求,数据需层层传递,势必会造成一定的性能下降。
- 成本增加:分层架构层次过多会增加开发成本。
4.2 表示层
表示层也称用户界面、UI层,负责直接与用户进行交互。表示层测试的主要目的是发现应用程序的用户界面问题,对于建立一个友好的、易操作的、健壮的应用至关重要,业务功能的正确性可不作为本层测试的重点。
(1)表示层的质量特性:
- Web端涉及的质量特性:可移植性、易用性、性能效率
- PC端涉及的质量特性:可移植性、易用性、功能性
- 移动端涉及的质量特性:可移植性、易用性、性能效率、功能性、安全性
(2)表示层的测试策略如下:
1)在软件需求分析和用户界面设计阶段,测试人员的职责是参与同行评审,了解软件需求和用户界面要求,以及使用场景和用户特点,根据经验,从测试角度提出建议。
2)测试人员在用户界面设计阶段结束后,可以提出对易用性问题的主观看法。
3)在测试设计阶段,测试人员的职责是根据软件需求规格说明书、用户界面设计以及软件人机交互友好性、易用性的测试准则设计测试用例。
4)在测试实施阶段,测试人员的职责是执行测试用例。
5)由于版本的更新,需求的更动,可能会涉及用户界面的回归测试。注意控制测试阶段中用户界面测试的时机和次数。
6)在上线之前,用户界面测试与功能测试同步确认一次,保证与最终版本的一致性。
7)一般情况下表示层测试不作为专项测试内容,可以与其他质量特性的测试混合进行。
4.3 服务层
随着互联网、移动应用的普及和应用复杂度的增加,为解决业务逻辑层和表示层的解耦,以实现对多种用户界面技术的支持,越来越多的技术采用接口服务层作为统一的接口管理层,也称为服务层。服务层测试就是独立于用户界面外对应程序服务进行的测试,需要使用避开用户界面的测试方法,对应用服务进行输入并验证其响应的测试。
(1)服务层的测试主要是接口测试,涉及的质量特性包括以下三种:
1)功能性:接口功能性可以分成输入、处理、输出三个部分。输入的测试主要是针对参数的数据类型和长度的检查。对于输出的测试,则是要覆盖各种响应码的返回结果,如正常的、异常的、失败的情况等。
2)信息安全性:常见的漏洞包括SQL注入、信息泄露、身份认证、访问控制、明文传输等,既存在传统应用程序中,也存在于API接口交互中。
3)性能效率:主要关注接口服务的响应时间、并发、服务端资源的使用情况等方面,不同层次性能测试的关注点不同。
4.4 业务逻辑层
业务逻辑层是实现系统业务功能的核心层,测试的依据主要是需求规格说明,测试目的是验证需求中的功能点是否都实现,且功能实现与需求描述相符合。
(1)业务逻辑层主要涉及的质量特性包括以下两种:
1)功能性:对业务逻辑层的功能性质量要求,主要体现在功能点测试和业务流程测试,通常采用黑盒测试。
2)信息安全性:业务逻辑层代码可能存在安全编码的问题,可以通过代码审计的测试方法进行测试。
(2)业务逻辑层的测试策略主要包括以下两种:
1)业务功能测试策略:包括测试需求分析(基于需求的测试分析、基于流程的测试分析、基于经验的测试分析)、测试用例设计(主要采用等价类划分法、边界值分析法、场景法等)、用例评审和测试实施执行四个方面。
2)代码审计测试策略:包括代码审计前期准备阶段、代码审计实施阶段、复测实施阶段和成果汇报阶段。
4.5 数据层
数据层测试主要是指对数据管理系统的测试。数据通常是一个组织最有价值的资产,应用程序可以重写,但是更换应用程序时不会丢弃满载数据的数据库,而是对数据库进行迁移。
(1)数据层涉及的质量特性有:可靠性、性能效率、安全性、正确性与完整性、功能性和可移植性。
(2)数据层的测试策略如下:
1)数据库可靠性策略:TPC-C测试程序的最大特点就是频繁的联机事务处理,因此它对后台数据库的稳定运行有较高的要求,可以借助TPC-C测试程序产生各种工作负载并进行可靠性验证。
2)性能效率策略:主要推荐TPC组织提出的性能测试标准和规范,目前常用的性能测试贵干主要有以下3种:
- 针对OLTP系统(联机事务处理)的性能测试规范TPC-C
- 针对电子商务应用的性能测试规范TPC-W
- 针对大数据基准测试(OLAP)的性能测试规范TPC-DS
3)数据库安全性策略:数据库安全性一般采用黑盒测试方法,以人工功能检查为主要形式,检查内容包括用户及口令管理、授权和审计管理、数据加密。
4)数据正确性与完整性策略:采用黑盒测试方法,通过图形化管理工具、交互式SQL工具等对数据库管理系统的功能特性进行测试,要求被测数据库提交图形化管理工具。由于该部分测试为功能验证性测试,因此以手工测试为主,包含以下测试内容:数据库存储数据的方式、数据类型和长度、数据日期和时间字段、国际化、字符集编码。
5)数据库功能性策略:测试点为安装与配置、数据库存储管理、模式对象管理、非模式对象管理、交互式查询工具、性能监测与调优、数据迁移及作业管理等8个方面。
6)数据迁移策略(数据可移植性):数据迁移的一般过程为前期调研、转换设计、数据整理、数据转换、系统切换、运行监控6个阶段。数据迁移的测试方法包括技术核验、静态对比、动态对比、业务连续性验证测试。