一般在接触测试时,都是从黑盒测试方法开始的,因为其技术相对简单一些,只需要关注外部条件,包括输入、输出结果,而不需要关注系统的内部结构。但随着测试的深入,测试人员将不满足于这种黑盒测试方法,开始关注被测试系统的内部构造,并逐渐深入,比如以下从系统的架构设计到代码实现的思考。
1) 根据系统的内部结构,采取相应的对策实现。例如,数据层和业务逻辑层,都可以采用API直接调用的测试方法。
2) 在代码层,根据程序结构,分别采用代码覆盖、分支覆盖、条件覆盖等方法来设计测试用例。
从这个演化的过程,可以隐隐约约地看到测试架构的形成。为了真正能解决问题,需要提高测试效率和测试覆盖率。测试不是单纯的,测试的方法也不是一成不变的,而且还要有系统性。
从测试结构来看,不仅要了解全部的测试内容,从单元测试到系统测试、从功能测试到非功能测试,如“附录B 软件测试的详细分类”,而且需要在分析、归纳和总结的基础上,将测试抽象到更高层面;提纲挈领,从整体上更好地把握测试任务。下面,将就功能测试和非功能测试分别讨论,而自动化测试架构,留到下一节讨论。
撇开非功能性测试,先谈软件产品的功能测试,以此来分析软件测试的架构。在功能测试中,不仅要完成业务逻辑的验证,还要进行用户界面和输入空间的验证。我们在讨论软件测试方法时,经常谈到的黑盒方法中的等价类划分、边界值分析、决策表、因果分析等方法,实际上都只是功能测试的冰山一角,仅为对输入空间的验证。为了使软件具有更好的质量,包括低缺陷率和高稳定性、可维护性,需要在代码这个层面进行充分的测试,就是人们常提到的单元测试,特别是对代码的评审、通过工具对代码进行静态分析。也就是说,在功能测试中,不光要进行不同层次的测试,还要针对不同空间或领域进行相应的测试,可以用图2-3简要加以描述。
图2-3 不同视角看功能测试
如果展开讨论,不同的测试领域会侧重采用不同的测试方法,如基于用例的测试,主要用于用户界面测试,但也会用于业务逻辑验证;而基于模型的测试,主要用于语法验证和业务逻辑验证等。图2-4系统地介绍了不同测试领域的测试方法,其中几个用英文书写的说明如下:
●FSM(Finite State Machine,有限状态机)
●ForS(Formal Specification,形式规格说明)
●FunS(Functional Specification,功能规格说明)
图2-4 功能测试架构示意图
这些测试方法构成了功能测试的架构,即设计一个软件项目的测试功能,就要从用户界面验证、业务逻辑验证、输入空间验证和语法验证4个方面去考虑。针对不同的方面,根据软件应用系统的技术特点等,选择或决定合适的测试方法、工具等,也是测试架构这个层面需要考虑的。
如果从非功能测试角度来考察测试架构,其和软件开发的架构更为贴近,两者在技术要求上是一致、相通的。非功能测试要追溯到设计阶段,软件设计是前提,设计不好,实现得再好可能也无济于事。所以,非功能测试可以看做由两大部分组成。
1) 设计验证: 这是纸上谈兵,针对系统设计说明书进行评审,发现设计的缺陷,因可防患于未然而显得更为重要。这也是和开发人员在思路上的辩论,针锋相对地提问,通过讨论甚至辩论来发现问题。
2) 系统验证: 将设计付诸于实施,针对建成后的系统进行验证,以确定系统是否达到设计要求。当然这一步也非常重要,设计得再好,还是要看实际的结果。
对于非功能性测试架构,要在对系统设计和构造理解的基础上来确定测试的具体方法。可以用简单的图来描述,如图2-5所示。
图2-5 非功能性测试的架构示意图
每一类测试可能需要单独考虑,性能测试和兼容性测试、安全性测试都不一样,不同类型的测试,考虑的着眼点不一样,其方法也不一样,所使用的测试工具也不一样。当然,压力测试、稳定性测试可以和性能测试一起考虑。这里以性能测试为例,其包括如下的关键因素。
1) 测试环境: 构造和产品实际运行相当的测试环境。
2) 关键业务: 根据系统的设计和实现,判断可能存在性能风险的业务操作点。
3) 负载: 根据系统的负载,确定可能受到的最大负载、平均负载等。
4) 监控指标: 哪些系统资源是有限的而且会产生瓶颈,需要在测试过程中被监控。
5) 结果分析: 通过对测试结果分析,确定性能问题,并分析造成性能缺陷的根本原因。
分析上面这些因素可知,构造一个良好的性能测试解决方案,关键还是要对系统实现全面了解,特别是对被测试的特性(这里指性能)要理解,能把握外部因素对系统的被测试特性的影响,从而确定系统测试的输入和测试的输出。除此之外,我们还得用技术的办法来模拟负载、监控系统的资源或响应,这实际上就是我们经常讲的建模,用逻辑的模型或数学模型来描述实际的物理模型,如图2-6所示。
图2-6 非功能性测试的建模(系统模拟)