当前位置:文档之家› 关于形式化方法与软件可靠性

关于形式化方法与软件可靠性

形式化方法与软件可靠性作者:郭洋摘要:形式化方法是一种基于数学的表示方法。

它能帮助发现其它方法不容易发现的系统描述的不一致,不明确或不完整,有助于增加软件开发人员对系统的理解,因此形式化表示方法是提高软件系统,特别是提高安全苛刻系统的安全性与可靠性的重要手段。

软件测试作为提高软件可靠性的一种形式化方法,在不同层次不同阶段可采取不同的方式方法。

测试覆盖准则是判断测试充分性的重要手段。

关键词:形式化方法;软件;可靠性;软件测试;测试覆盖形式化表示方法的出发点是数学逻辑方法。

其目的是开发可靠的软件产品。

以目前常用软件开发方法为出发点,主要研究怎样将这些方法形式化,使软件系统的描述更精确化,以减少可能的误解所带来的问题;或以目前常用的软件开发过程为出发点,研究怎样在软件开发过程中增加一些形式化方法的应用,以提高软件的可靠性。

1 什么是形式化方法形式化方法是描述系统性质的基于数学的技术。

这样的形式化方法提供了一个框架,人们可以在框架中以系统的而不是特别的方式刻划、开发和验证系统。

如果一个方法有良好的数学基础,那么它是形式化的,典型地以形式化规约语言给出的。

这个基础提供一系列精确定义的概念,如一致性和完整性,以及更进一步,定义规约、实现和正确性。

形式化方法的一个重要研究内容是形式规约,它是对程序“做什么”的数学描述,是用具有精确语义的形式语言书写的程序功能描述,它是设计和编制程序的出发点,也是验证程序是否正确的依据。

对形式规约通常要讨论其一致性和完备性等性质。

形式规约的方法主要可分为两类:一类是面向模型的方法也称为系统建模,该方法通过构造系统的计算模型来刻画系统的不同行为特征;另一类是面向性质的方法也称为性质描述,该方法通过定义系统必须满足的一些性质来描述一个系统。

不同的形式规约方法要求不同的形式规约语言,即用于书写形式规约的语言,如代数语言One/Two等;进程代数语言;时序逻辑语言等;这些规约语言由于基于不同的数学理论及规约方法,因而也千差万别,但它们有一个共同的特点,即每种规约语言均由基本成分和构造成分两部分构成。

前者用来描述基本规约,后者把基本部分组合成大规约。

构造成分是形式规约研究和设计的重点,也是衡量规约语言优劣的主要依据。

形式化方法的分类:(1)根据说明目标软件系统的方式,形式化方法可以分为面向模型的形式化方法和面向属性的形式化方法。

(2)根据表达能力,形式化方法可以划分为基于模型的方法、基于逻辑的方法、代数方法、过程代数方法、基于网络的方法。

2 软件可靠性的定义软件可靠性是软件系统固有特性之一,它表明了一个软件系统按照用户的要求和设计的目标,执行其功能的正确程度。

软件可靠性与软件缺陷有关,也与系统输入和系统使用有关。

理论上说,可靠的软件系统应该是正确、完整、一致和健壮的。

但是实际上任何软件都不可能达到百分之百的正确,而且也无法精确度量。

一般情况下,只能通过对软件系统进行测试来度量其可靠性。

软件可靠性给出如下定义:“软件可靠性是软件系统在规定的时间内及规定的环境条件下,完成规定功能的能力”。

根据这个定义,软件可靠性包含了以下三个要素:(1)规定的时间:软件可靠性只是体现在其运行阶段,所以将“运行时间”作为“规定的时间”的度量。

“运行时间”包括软件系统运行后工作与挂起的累计时间。

由于软件运行的环境与程序路径选取的随机性,软件的失效为随机事件,所以运行时间属于随机变量。

(2)规定的环境条件:环境条件指软件的运行环境。

它涉及软件系统运行时所需的各种支持要素。

不同的环境条件下软件的可靠性是不同的。

(3)规定的功能:软件可靠性还与规定的任务和功能有关。

由于要完成的任务不同,软件的运行剖面会有所区别,则调用的子模块就不同,其可靠性也就可能不同。

所以要准确度量软件系统的可靠性必须首先明确它的任务和功能。

3 形式化方法与软件可靠性的关系随着软件的广泛应用,特别是软件在尖端领域的应用,软件可靠性成为一个非常重要的问题。

软件的可靠取决于两个方面,一个是软件产品的测试与验证,另一个是软件开发的方法与过程。

对简单的软件开发,应该是先有对软件的需求,然后对软件进行设计,然后是编写程序,最后是对程序进行测试。

对复杂的软件系统,总的过程基本还是这样,只是各个阶段也相应复杂一些。

形式化表示方法在软件开发中能够起到的作用是多方面的:(1)首先是对软件要求的描述。

软件要求的描述是软件开发的基础。

比如说一般非形式化的描述很可能导致描述的不明确和不一致。

如果描述的不明确和不一致导致设计,编程的错误,将来的修改所要付出的代价就非常大了。

如果导致的错误没有被发现,则影响程序的可靠和使用。

形式化方法则要求描述的明确性,而描述的不一致性也就相对易于发现。

(2)其次是对软件设计的描述。

软件设计的描述和软件要求的描述一样重要。

形式化方法的优点对于软件要求的描述同样适用于软件设计的描述。

另外由于有了软件要求的形式化描述,我们可以检验软件的设计是否满足软件的要求。

对于编程来讲,我们可以考虑自动代码生成。

对于一些简单的系统,形式化的描述有可能直接转换成可执行程序,这就简化了软件开发过程,节约了资源和减少了出错的可能性。

(3)另外,形式化方法可以用于程序的验证,以保证程序的正确性。

对于测试来讲,形式化方法可用于测试用例的自动生成,这可以节约许多时间和在一定程度上保证测试用例的覆盖率。

形式化方法的意义在于它能帮助发现其它方法不容易发现的系统描述的不一致,不明确或不完整,有助于增加软件开发人员对系统的理解,因此形式化方法是提高软件系统,特别是安全苛刻系统的安全性与可靠性的重要手段。

早期形式化方法在软件验证的应用是串行程序的验证,后来随着软件研究和应用的发展,逐渐多样化。

近年来,由于认识到形式化方法重视的是严谨性,逐渐有许多结合图形化软件方法、面向对象方法和形式化方法的工作。

对于复杂的软件系统的验证,最好是能够结合多种方法的使用。

这些方法对提高软件可靠性的探索和应用都极为重要。

4 软件测试软件测试作为软件可靠性保障的重要手段,本身就是一种形式化方法。

测试是基于给定的准则对系统的执行进行抽样的一个过程。

测试过程将系统的每次执行与规约进行比较,并将其中的不一致作为错误报告。

由于测试通常是对系统执行的抽样,而不是检查所有的系统执行,所以并不能保证所有的错误都能被覆盖到。

尽管测试并不能保证会发现给定程序中的所有错误,但测试易于进行,并能以合理的开销提高系统的可靠性。

特别是与演绎验证相比,测试所需要的时间开销和人力资源均明显要少。

当验证难于实施,模型检验不可行时(例如,在出现无限的或巨大的状态空间,或者复杂的数据结构时),测试方法往往仍然是适用的。

软件测试包括下面几个层次和阶段:单元测试:最底层的测试阶段,对代码的小片段单独进行测试。

集成测试:对多个代码片段协同进行测试,这些代码片段可能是由不同团队开发的。

系统测试:将系统作为一个整体进行测试,通常用于审查软件的功能性。

验收测试:通常由用户进行,检查所开发的系统是否满足其需求。

回归测试:在维护阶段进行,当对系统中的部分模块进行修改、校正或者升级时,检查系统各项功能是否仍能正确运行。

回归测试通常在为已测试系统增加新功能时使用。

5 控制流覆盖准则控制流覆盖准则是在单元测试中经常使用的一种用于设计测试用例并衡量测试充分性的测试方法。

在单元测试中,一个测试用例通常对应于所选择的一条执行路径。

路径可以进行选择,比如可以通过指定初始值和执行过程中所需要的输入来进行选择。

(然而,在程序可能出现非确定性行为时,比如存在并发的时候,指定初始值和输入不足以完全控制整个执行过程。

)测试人员可以执行一条路径并将输出结果与预期的输出进行比较。

测试过程中。

假定测试人员对待测系统正确的行为是已知的,并能发现待测程序实际行为的偏差。

在测试过程中,很少会采用完整地检查系统所有执行的方式。

因此,测试通常是基于特定的覆盖准则进行的。

按照一定的覆盖准则,可以将可能会发现同样错误的执行归为一个集合(在实践过程中,测试发现的可能是引发错误的缺陷源,而并不总是错误)。

然后测试人员在每一个集合中抽取一个作为执行样本。

例如,可以将沿着待测程序对应的流程图中同一条路径运行的执行归为一个集合。

总而言之,集合数量越大,每个集合所包含的测试用例的数量就越小。

通常(但并不一定)一个覆盖准则需要检查的执行路径越多,发现程序中潜在错误的可能性就越高,但完成测试所需要的工作量也越多。

覆盖准则可以被视为检验代码的启发式方法,其中一些覆盖准则将在下面介绍。

接下来本文将介绍几种主要的覆盖准则并通过一个示例来说明它们之间的区别。

图1 是示例程序的一部分所对应的流程图。

该示例不需要用户提供输入。

本文将基于所介绍的各种覆盖准则,给出针对该流程图的一些测试用例的示例。

图1为更好地使用这个特定的例子来强调覆盖准则的不同,在测试用例中使用在判定谓词x≡y∧z> w。

之前(即刚刚递增了y 之后)变量状态来描述。

但在一般情况下,在路径入口处采用赋值表达式来描述测试用例更为合理,因为我们可以适当地对测试进行初始化。

5.1 语句覆盖程序中的每条可执行语句(例如,赋值、输入、判定、输出)在至少一个测试用例中出现。

对语句覆盖准则,可以使用下面的赋值使判定谓词x≡y 和z>w 的计算值均为TRUE:{x↦2。

y↦2,z↦4,W↦3} 测试用例1值得注意的是这样不能覆盖到判定谓词的值为FALSE 的情况。

因此,可能会缺失某些选择false边的情况所需的必要的计算,但未在代码中出现。

5.2 边覆盖流程图中的每条可执行边都在某测试用例中出现。

特别地,在此覆盖准则下,需要覆盖待测程序所有判定谓词的true和false 分支(例如if-then-else 命令,或者while循环)。

边覆盖准则也常被称为分支覆盖或者判定覆盖。

为满足边覆盖准则,需要在测试用例1的基础上增加另一个测试用例,用以检查谓词的判定值为FALSE 的情况,使该测试用例在判定节点选择false 边。

增加的测试用例为:{ x↦3,y↦3,z↦5,w↦7} 测试用例2测试用例1和2将判定谓词x≡y∧z>w作为一个单独的单元来覆盖,而并未作为两个独立的条件来考虑。

后一个测试用例中选择false 出边是因为Z>W 不能被满足。

但条件x≡y 可能是错误的,例如应该是x≥y。

当x>y 时,递减x 的语句仍然应该被执行到,而这种情况目前未能被测试到。

在对布尔运算符使用“短路”规则的程序设计语言中,将判定谓词作为一个整体来测试会带来问题。

在该规则中,形如A∧B 的表达式,当A 的值为FALSE 时,整个表达式的值将判定为FALSE ,而不需要求B 的值。

类似地,形如AVB 的表达式,当A 的值为TRUE 时,整个表达式的值将判定为TRUE,而不需要求B的值。

相关主题