带你读《基于模型的测试:一个软件工艺师的方法》之二:流程图

简介: 本书主要讨论基于模型的测试(MBT)技术。作为一门手艺而非艺术,其关键在于:对被测软件或系统的理解,选择合适工具的能力,以及使用这些工具的经验。围绕这三个方面,书中不仅综合阐述了MBT的理论知识及工具,而且分享了作者的实战经验。

点击查看第一章
点击查看第三章

第2章

流程图
计算机领域很早就开始使用流程图(flowchart)了,这可能是使用最早的一类行为模型。在20世纪60年代,工具供应商通常会提供一些具有可塑性的流程图模板,程序员可以据此绘制出更整齐的流程图。IBM公司甚至提供了一个带有基本标记的不同规格标准的流程图模板。前辈们开玩笑说,这是该领域的第一个CASE(计算机辅助软件工程)工具。

2.1 定义与表示法

通常有两种不同风格的流程图标记形式。图2-1所示为第一种,这是一种极简风格的表示方式,只有表示动作、决策和两种页连接符的符号。分页连接符一般用于不能在一页上显示完全的大型系统中。传统的分页连接符使用大写字母ABC…,第一个分页连接符是A,与之对应的连接点也用A表示。
在流程图使用的早期,因为比较关心系统的输入/输出设备,所以开发出很多扩展的流程图符号,如图2-2所示,这里面甚至有表示卡片式I/O的符号。
 

image.png

在这种流程图标记方式中,“?流?”的部分使用带箭头的线段,表示从某个流程图符号开始,在某个流程图符号处结束。图2-3是特浓咖啡自动售卖机的流程图示例,利用这个咖啡机,可以用1欧元买到一小杯意大利特浓咖啡。后续我们还会使用这个案例讨论流程图技术。

2.2 技术详解

图2-3中的流程图能够处理自动售卖机的销售过程。接收欧元硬币,给出特浓咖啡。如果仔细观察流程图,可能会注意到,所有的箭头都会在符号的顶部结束。这不是强制要求,但这样做有助于理解。决策框只能有一个入口,既然是决策过程,那么至少应有两个出口箭头。在早先的Fortran年代,“Arithmetic IF”语句带有3个输出。这个钻石形状的框(决策符号框)的边与底部顶点可以分别表示3种选择(<、=、>)。在图2-3中很容易看到这3个选项。如果多于3个选项(比如Case/Switch语句),每个选项对应一个连接箭头即可。(标识符是为使用者服务的,不必非要遵守条条框框)。过程框则最多只有一个输出箭头。但它们可能有多个输入箭头。箭头上的标签通常表明决策框有几个可能的出口,Yes/No、True/False或者数值显示决策结果。从过程框发出的箭头则没有标签。这样表示过程框的过程是完整的,流程走向下一个框。框之间不会表达信息或内容。使用者需要自己确定过程框的结果对于后续框是否可用(流程图具有“记忆性”)。

image.png

对于过程框和决策框来说,框内文本内容几乎没有限制,可以有不同的形式,这些形式的抽象程度也可以不同。框内文本可以简明扼要,如图2-3所示。或者也可以非常具体,甚至可直接是某种编程语言。例如“硬币是”决策框的输出结果可以是1.00欧元、0.50欧元或0.20欧元三种形式。同样,决策条件也可以表示为针对每一种硬币类型的二进制条件,如“是”或“否”。不管使用哪种方式,最好要保持一致,如果不同抽象级别的文本表达混合在一起,那将是很让人困惑的。流程图的符号集可以支持结构化编程的3种基本结构:顺序、选择、循环。例如图2-3所示的决策框表示了“选择”结构,而图2-3底部还有一处表示了“循环”结构:如果变量“总金额”与1欧元的比较结果是“小于”,就会返回到投入硬币过程框。再看一下1欧元那个分支,它结束“提供特浓咖啡”这个过程框,这正是“顺序”结构的例子。在结构化编程中,通常有“单一入口,单一出口”的设计惯例,但是这个惯例并不是强制要求,图2-3所示例子是符合这个惯例的。
流程图采用分层策略来处理不同抽象级别的过程。也就是说,一个高抽象级别的过程框可以扩展成一系列更详细、单独的流程图。如果这样做,那么每一个低抽象级别的流程图都应该被命名,以此来清晰地表明它是从某个高抽象级别的过程框扩展而来的,或者干脆使用分页连接符(只是分页连接符的方式显得有些笨重)。本章结束部分的表2-4,总结了在流程图中可以表达的控制事件。

2.3 案例分析

2.3.1 日期计算函数

NextDate函数是测试圈里非常流行的一个例子,它非常简单,很容易找到测试用例的预期输出。(给定某个日期,NextDate函数返回下一个日期。)图2-4和图2-5采用分层流程图方式将功能进行了分解。变量lastDay的数值通过其他方式计算出来,然后与决策框中的日期进行比较。如果某个变量可以在多处赋值,那么必须保证最终计算出来的数值在运行过程中不会相互改写。在NextDate流程图中,有3个值被分配给nextDay、nextMonth和nextYear。决策框要求这3个赋值必须是互斥的。在这些计算过程中使用到了GoTo语句,当使用流程图来建立主要的行为模型时,使用GoTo语句是一种常用作法。在流程图中可以清晰地看到,NextDate函数的逻辑是很严密的。

image.png

2.3.2 风寒指数表

著名的风寒指数(密歇根州或者其他寒冷地区)是由两个变量构成的函数:每小时风速V和摄氏温度T。其公式如下所示:
image.png
其中,W是人脸的表面温度,以华氏度为单位;T是空气温度,以华氏度为单位,
-20≤T≤50;V是风速,以mile/h(1mile?=?1609.34m)为单位,3≤V≤73。
基于图2-6所示的流程图可以完成一个类似表2-1的表格,请注意其中的循环嵌套。

image.png

image.png

(例子中的数值范围是随意制定的,在密歇根州,这是真实情况!)风寒表格中温度的范围是-20℉≤T≤50℉,每次递增5℉;风速范围是3≤V≤73,每次递增5mile/h。

2.3.3 保费计算流程图

图2-7是1.8.1节中定义的保费计算问题的流程图模型。

2.3.4 车库门控系统流程图

图2-8是1.8.2节中定义问题的流程图模型。

image.png

image.png

2.4 基于流程图派生的测试用例

流程图中的路径可以直接推导出抽象的测试用例。由于流程图可以显示并发的路径,因此很容易手工设计出相关的抽象测试用例。从图2-7所示的保费计算流程图中可以看到关于年龄和保费变量的并发路径。毫无疑问,并发路径应该是互斥的。(测试用例也可以利用某个指定流程图的语义内容派生出来,但这反过来又要求手动推导测试用例生成。)通常来说,从流程图中不可能直接设计出具体的测试用例,因为流程图只显示了需要完成的过程,并不实际执行这些过程。
(对于类似Fortran这样的程序来说,流程图很好用。)而对于事件驱动型应用来说,流程图的形式就显得不太适合了。从接下来给出的事件驱动示例,可以清晰看出以下几个问题。

  • 事件可以表示为决策的输出或者过程(过程框)。
  • 由于没有专门的事件标识符,所以事件只能表示为流程图中有明确语义的内容。
  • 需要具有洞察力和领域经验才能识别与上下文相关的输入事件。

2.4.1 保费计算问题的测试用例

图2-7所示的流程图中一共有40条不同的路径,其中36条对应着表2-2列出的使用等价类测试方法生成的测试用例。年龄和出险次数变量由变量的取值范围来定义,因此从表面上看,只需要测试某种形式的边界值就足够充分了。将每个等价类中的边界值映射到相同的乘法和加法函数集合中,它们会在结果中产生大量的冗余,因而这并无太大价值。图2-9显示了表2-2中测试用例1的路径。
表2-2显示了保费计算问题的抽象测试用例和具体测试用例。抽象测试用例可以从流程图中直接设计出来(MBT工具可以完成这个过程)。实际数值则需要从需求中获取。从图2-7中给定的文本可以看出,对于MBT工具来说,直接生成测试用例需要的实际数值还是很困难的。我主要使用电子表格中的替换功能来完成这部分工作,这样还不算太麻烦。通常来说,电子表格是MBT工具很顺手的一个补充。
下面是图2-8所示路径对应的测试用例1中的抽象和具体测试用例。

image.png

image.png

image.png

2.4.2 车库门控系统的测试用例

在车库门控系统的流程图中有两个循环:一个是停下并重启正在关闭的门,另一个是停下并重启正在打开的门。(一个是在关门过程中停下或者重启,一个是在开门过程中停下或者重启。)如果假设输入事件和输出过程是同时发生的,那么数学家会说,在图2-8所示的流程图中,存在一个含有不同路径的可数无穷路径集合。在实际生活中,我家的车库门需要大概13s关闭或者开启,而停止/重启序列需要大概1s,因此,实际上车库门流程图只有一个有限数目的可能路径。图2-10显示了其中一条路径,该路径由下面的测试用例来表示。图2-10所示的流程图符号是有编号的,以表示路径的追踪和命名。

image.png

表2-3包含车库门流程图中的5条不同路径。我们先简要描述一下每条路径(也可以视之为用户场景),然后再使用按系列编号的流程图符号来详细描述它们。5条路径涵盖了每个流程图符号和流程图中的每条边。另外还有些路径是针对光束被打断之后的过程的,这些路径也包括每个上下文的控制设备的输入事件。对于工具来说,很难从流程图中设计出详细的、类似使用用例(use case,从用户角度考虑的使用场景)的测试用例。

image.png

image.png

表2-4包括从图2-8所示流程图中设计出的手工测试用例信息。从中我们可以看出,流程图的定义存在一些“小问题”,原因如下:
1)输入事件看上去既可以是决策框的输出,也可以是过程框中表示的一个过程;
2)事件上下文(状态)看上去是与过程框对应的过程,也可以说是决策框的输出;
3)有两个潜在的死循环:正在开门或者关门时停止。
除非具有领域经验,否则,利用输入事件/输出过程对是没有办法定位下一步操作的。

2.5 优势与局限

流程图有很多优势。如果任何一种表达方式已经使用了数十年,那么它肯定还是有可取之处的。对于流程图来说,这个优势就很容易理解。由于过程框和决策框里面的文本可以使用自然语言,因此流程图使客户和开发者之间具有更好的交互性。就连美国的IRS都是用流程图来解释复杂的税务代码的。如我们之前所说,流程图能够表达基本的结构化编程架构。其中,还有没有明确说明的地方,这就是对于流程图中“存储器”功能的使用。如果一个变量在过程框中被赋予一个值,那么该变量在后续需要保持这个数值。在图2-3中可以清楚地看到,变量“总金额”被定义之后,在之后的循环中可以再次定义它。任何“形式化好的”流程图都可以使用命令式和结构化的编程语言进行编码。如示例中所示,流程图支持几种级别的抽象,因此它们具有可扩展性,能够描述大型而且复杂的应用。另一个优势是,它们可以用来描述复杂的计算和算法。最后一个优势是有些控制过程或者行为可以通过流程图中不同的路径来表达。

image.png

流程图也有些限制。由于流程图的本质是将过程序列化,所以很难表达事件驱动的系统,因为在事件驱动的系统里面,独立事件可能以任何顺序发生。此外,流程图很难描述被描述系统需要操作的外部设备的上下文。虽然面向设备的I/O符号可以完成这个工作,但是需要很多扩展。流程图几乎没有办法表达数据,除非是在过程框或者I/O框里面。过程框和决策框里面的文本可以包含变量名,但这是很粗浅的表达。数据表达都如此困难,表达数据结构以及数据之间的关系就更难了。同样,对于描述事件,它也有很多潜在的困难。从图2-8中可以看到,设备控制信号有时表示为过程框,有时又显示为决策框的输出。表2-5将流程图的描述能力与第1章定义的标准列表进行了对比。

image.png
image.png

2.6 经验教训

在20世纪60年代晚期,电话交换机系统开发实验室需要将所有的交互系统源代码的流程图文档提供给运营公司。当时,源代码大概是30万行的汇编程序。在这个过程中,软件工程师需要向图案部提交手绘流程图,六周以后,软件工程师就可以得到非常完美的流程图。在这六周内,如果设计师想要对流程图进行修改,那么他们可以将原始草图替换成修改之后的草图,以免在图案部里重新排队。
同时,我的管理团队中的一位数学家参加了一次研讨会,会上他看到一个程序,这个程序能够在CalComp绘图机上画出离散部件电路图。我们研究了技术资料后,决定将电路图符号替换成流程图符号,结果就产生了AELFLow系统[Jorgensen和Papendick 1970]。这是我们学到的第一个经验:为了使绘图机能够得到认可,我们向每个部门展示了他们如何从绘图机上获益。推销了几周之后,我们最终得到许可购买了最小的绘图机。6个月之后,我们有了最大的绘图机。AELFlow系统非常有效,不仅节约了返工的时间,而且提高了设计文档的整体可用性。相比汇编代码,流程图更容易从技术角度进行描述。从各方面来看,AELFlow系统都是真正的CASE工具,这比术语CASE的使用要早得多。
这里关键的教训是:变革是很难引入的,它需要时间、耐心和对企业的认知,同时也需要培训。尽管对于AELFLow系统来说,培训是很少的一部分。Gartner Hype的周期是相当精确的,尽管持续的间隔可能有变化(如图2-11所示)。准备引入MBT的组织一定要经历宣传周期。我的观点是,期望膨胀的峰值期源于MBT产品的销售团队,泡沫破裂的幻灭期则源于不同模式的不充分的培训和教育。稳步爬升的复苏期开始于合适的工具和良好的模式教育,实质生产的成熟期则随着市场的关注度和占有率而保持。

image.png

参考文献

image.png

相关文章
|
13天前
|
测试技术 持续交付 UED
探索自动化测试框架:提高软件质量的利器
在软件开发周期中,自动化测试框架扮演着至关重要的角色。本文将深入探讨自动化测试框架如何提升测试效率、确保软件质量和促进持续集成/持续部署(CI/CD)的实施。文章将分析自动化测试的优势、挑战以及实施策略,为读者提供一份全面的自动化测试指南。
|
15天前
|
敏捷开发 测试技术
软件测试中的探索性测试方法
【6月更文挑战第12天】探索性测试,一种灵活的测试实践,旨在通过自由形式的探索发现软件的潜在缺陷。它不依赖于事先编写的测试用例,而是鼓励测试人员利用直觉、经验和创造力来指导测试过程。本文将深入探讨探索性测试的核心概念、实施策略以及它如何增强传统测试方法的有效性。
|
1天前
|
数据采集 数据可视化 测试技术
C#生成Selenium测试报告:实用方法与技巧
在C#中使用Selenium进行自动化测试时,结合代理IP和ExtentReports能增强测试安全性和报告质量。安装必备工具如Selenium WebDriver、NUnit和ExtentReports。在测试设置中,配置代理(如亿牛云爬虫代理)以隐藏IP,通过ChromeOptions定制UserAgent,并添加Cookie。测试代码示例展示了如何打开网页、执行搜索并生成详细的测试报告。使用ExtentReports可创建可视化测试结果,便于团队分析。
C#生成Selenium测试报告:实用方法与技巧
|
9天前
|
监控 数据管理 测试技术
自动化测试:提升软件质量的关键
【6月更文挑战第19天】自动化测试在软件质量保障中至关重要,通过使用工具执行测试用例,提高效率、减少错误。关键技术包括测试框架(如Selenium)、测试脚本编写、测试数据管理和测试执行监控。虽面临脚本维护、数据管理等挑战,但自动化测试能提升软件质量,降低成本,加快交付速度,并将在未来持续影响软件行业。
|
7天前
|
机器学习/深度学习 敏捷开发 人工智能
自动化测试的崛起:如何利用AI提升软件质量
【6月更文挑战第20天】在软件开发的浪潮中,自动化测试已成为确保产品质量的关键工具。随着人工智能(AI)技术的飞速发展,其在自动化测试中的应用日益广泛,为测试流程带来了革命性的变化。本文将探讨AI如何优化测试用例生成、提高缺陷检测效率和预测潜在问题,从而显著提升软件测试的效率和准确性。
28 3
|
8天前
|
芯片
LDO的原理及测试方法
LM317是一种可调稳压器,核心是Bandgap Reference,用于提供1.25到37V的输出电压和1.5A的电流。了解其内部结构有助于测试和电路设计,例如理解温度系数对稳定性的影响,以及参数如IADJ(通常为50uA)的设计。测试时关注输出电压的线性和负载调整率,同时注意输入电流与输出电流的关系。LM317的测试还包括参考电压、滤波器性能、纹波抑制比等,确保电路的稳定性和效率。在多站点测试中,还需确保辅助电路的一致性和校准。
19 4
|
9天前
|
敏捷开发 测试技术 持续交付
探索式测试在软件质量保证中的角色与实践
【6月更文挑战第18天】探索式测试,一种灵活且高效的软件测试方法,正逐渐改变传统测试流程的面貌。本文将深入探讨探索式测试的核心概念、实施策略及其在现代软件开发生命周期中的应用价值。通过案例分析与实证研究,揭示探索式测试如何提升测试覆盖率,增强团队协作,并促进持续集成与交付。最终,文章旨在为读者提供一套实用的探索式测试框架,以支持其在软件质量保证活动中的有效运用。
11 3
|
9天前
|
敏捷开发 运维 Devops
现代软件测试方法与挑战
在当今高度数字化和技术化的时代,软件测试成为保证产品质量和用户体验的关键环节。本文探讨了现代软件测试方法的演进和面临的挑战,从传统到自动化测试的转变,以及如何应对复杂性和快速变化的软件开发环境。
|
9天前
|
敏捷开发 测试技术
软件测试中的探索性测试方法
【6月更文挑战第18天】本文将深入探讨探索性测试(Exploratory Testing)在软件测试领域的重要性与实施策略。不同于传统的脚本化测试,探索性测试强调测试人员的主观能动性和创造性,以真实用户的角度出发,发现那些可能在规范性测试中被忽视的问题。文章首先介绍探索性测试的定义和优势,然后通过案例分析,展示如何有效执行探索性测试,最后讨论其在敏捷开发环境中的适应性以及如何与传统测试方法相结合以提升测试覆盖率和效率。
|
11天前
|
敏捷开发 机器学习/深度学习 人工智能
现代软件测试方法与挑战
随着信息技术的迅猛发展,现代软件测试面临着越来越复杂的挑战。本文探讨了当前流行的软件测试方法及其在应对不断增长的复杂性和新兴技术方面的应用。重点讨论了自动化测试、敏捷开发以及人工智能在软件测试中的应用,以及它们如何改变了测试团队的角色和策略。最后,文章还分析了未来软件测试面临的可能发展趋势和挑战。