当前位置: 首页 > news >正文

基于有限状态机的测试(五):关键技术(自适应区分序列、识别序列)

要验证现实状态机模型B和理想状态机模型A的相似性,以及B中各个状态迁移的正确性,核心问题在于如何判断被测对象所处的状态。围绕这一问题发展出来的种种技术,就成为了基于有限状态机的测试方法中的关键部分。

本篇我们继续讨论这些关键技术。


7. 复位序列

严格来说,自适应区分序列并不是一个输入序列,而是一棵决策树。例如,对于图7所示状态机A:

图7

其自适应区分序列如图8所示:

图8

决策过程如下:

(1) 首先尝试给A输入a。如果输出是0,说明初始状态可能是s1、s3或s5,当前状态可能是s2(对应初始状态s1)、s4(对应初始状态s3)或s6(对应初始状态s5);

(2) 然后输入a,输出必然为1,当前状态可能是s3(对应初始状态s1)、s5(对应初始状态s3)或s1(对应初始状态s5);

(3) 然后输入b,输出必然为0,当前状态可能是s4(对应初始状态s1)、s6(对应初始状态s3)或s1(对应初始状态s5);

(4) 然后输入a:

  (4.1) 如果输出为0,则当前状态只能是s2(对应初始状态s5),这就找到了一个叶节点,说明状态机的初始状态是s5。也就是说,当输入序列aaba对应的输出是0100的时候,就能识别出状态机的初始状态是s5;

  (4.2) 如果输出为1,则当前状态可能是s5(对应初始状态s1)或s1(对应初始状态s3)。

  (4.3) 继续输入b,输出必然为0,当前状态可能是s6(对应初始状态s1)或s1(对应初始状态s3)。

  (4.4) 继续输入a:

    (4.4.1) 如果输出为1,则当前状态只能是s1(对应初始状态s1)。也就是说,当输入序列aababa对应的输出是010101的时候,就能识别出状态机的初始状态是s1;

    (4.4.2) 如果输出为0,则当前状态只能是s2(对应初始状态s3)。也就是说,当输入序列aababa对应的输出是010100的时候,就能识别出状态机的初始状态是s3。

最初输入a的时候,如果输出是1,则进入决策树的右侧分支,后续过程和左侧分支类似。

并非所有最简状态机都存在自适应区分序列。比如图6所示的最简状态机就不存在自适应区分序列,因为决策树既不能从输入a开始,也不能从输入b开始。

图6

一个状态机有可能并不存在预设区分序列,但却存在自适应区分序列。图7所示状态机就是这样的一个例子。

图7

假设这个状态机存在预设区分序列,那么预设区分序列只能从a开始,因为初始状态和当前状态的可能集合都是{s1, s2, s3, s4, s5, s6},如果从b开始,就会让当前可能状态s1、s2、s6发生归并。而输入a之后,初始状态区分和当前状态区分都是\pi\left ( a \right )=\sigma \left ( a \right )=\left \{ \left \{ s_1,s_3,s_5 \right \},\left \{ s_2,s_4,s_6 \right \} \right \},这时,下一个输入字符是什么呢?仍然只能是a,因为一旦输入b,就会让当前可能状态集合{s2,s4,s6}中发生归并。连续输入两个a之后,初始状态区分为\pi\left ( aa \right )=\left \{ \left \{ s_1,s_3,s_5 \right \},\left \{ s_2,s_4,s_6 \right \} \right \},并没有实现进一步的区分。后续输入更多字符的情况也是类似的。因此这个状态机不存在预设区分序列。

如果一个输入a不会导致当前可能状态集合C发生归并,我们称输入a对C而言是“有效”的,也就是说,\forall s_i,s_j \in C,i\neq j,都有\lambda(s_i , a) = \lambda(s_j, a)\delta(s_i , a) = \delta(s_j, a)。在自适应区分序列的输入决策过程中,每一步所面对的当前可能状态集合都是唯一确定的,每一步输入都只需要对这个集合是有效的。而预设区分序列的工作过程中,由于缺少输出的反馈信息,每一步所面对的当前可能状态集合有多个,每一步输入必须对所有这些集合都是有效的。这就是为什么有的状态机存在自适应区分序列,却不存在预设区分序列的原因。

仍然以图7所示状态机为例,来说明判定自适应区分序列是否存在的方法。

  1. 输入第一个a之后,当前状态区分为\pi_1=\left \{ \left \{ s_1,s_3,s_5 \right \},\left \{ s_2,s_4,s_6 \right \} \right \},其中包括两个当前可能状态集合。对第一个集合{s1,s3,s5}而言,输入b是有效的,且输入b之后,s1仍然在该集合中,s3和s5则会迁移到第二个集合中。这样,当前状态区分就更新为\pi_2=\left \{ \left \{ s_1\right \},\left \{s_3,s_5 \right \},\left \{ s_2,s_4,s_6 \right \} \right \}
  2. \pi_2中包括三个当前可能状态集合,对第三个集合{s2,s4,s6}而言,输入a是有效的,且输入a之后,s2和s4会迁移到第二个集合中,s6则会迁移到第一个集合中。这样,当前状态区分就更新为\pi_3=\left \{ \left \{ s_1\right \},\left \{s_3,s_5 \right \},\left \{ s_2,s_4\right \},\left \{s_6 \right \} \right \}
  3. \pi_3中包括四个当前可能状态集合,对第二个集合{s3,s5}而言,输入b是有效的,且输入b之后,s3会迁移到第三个集合中,s4则会迁移到第四个集合中。这样,当前状态区分就更新为\pi_4=\left \{ \left \{ s_1\right \},\left \{s_3\right \},\left \{s_5 \right \},\left \{ s_2,s_4\right \},\left \{s_6 \right \} \right \}
  4. \pi_4中包括五个当前可能状态集合,对第四个集合{s2,s4}而言,输入a和b都是有效的。如果输入b,s2会迁移到第一个集合中,s4则会迁移到第三个集合中。这样,当前状态区分就更新为\pi_5=\left \{ \left \{ s_1\right \},\left \{s_3\right \},\left \{s_5 \right \},\left \{ s_2\right \},\left \{s_4\right \},\left \{s_6 \right \} \right \}。至此,每一个当前可能状态集合中都只有一个状态,这时我们就能确定自适应区分序列是存在的。

显然,如果理想模型A存在自适应区分序列,那么其任一状态都存在唯一输入输出序列。但反之不然。假定其状态si的唯一输入输出序列是xi,那么该状态的划分集可以取为{xi}。由于自适应区分序列是从唯一的根节点生长出来的决策树,任意两个状态的区分序列都会有共同的前缀,所以\left \{ \left \{ x_i \right \},i=1,\cdots ,n \right \}是划分序列簇(由此也可知,唯一输入输出序列不能用于构造划分序列簇,因为不同状态的唯一输入输出序列不一定有共同的前缀)。因此,可以利用每个状态自己的唯一输入输出序列验证现实模型B与A的状态相似性,以及B是否正确实现了每个迁移。

仍然以图1所示状态机A为例:

图1

其自适应区分序列如图9所示:

图9

则状态s1的唯一输入输出序列x1=ab,状态s2的唯一输入输出序列x2=a,状态s3的唯一输入输出序列x3=ab。以下输入序列可以从初始状态s1开始遍历A的所有状态(最终回到s1),并验证B与A的相似性:

x_1 \tau(t_1,s_2)x_2 \tau(t_2,s_3)x_3 \tau(t_3,s_1)x_1=abababab

实际上,验证各个状态和迁移的输入序列中经常存在冗余,比如两个输入序列是完全相同的,或者一个输入序列是另一个输入序列的前缀。去除这些冗余,检查序列就可以得到简化。看另一个例子,假设A如图10所示:

图10

A的自适应区分序列如图11所示:

图11

则状态s1的唯一输入输出序列x1=bb,状态s2的唯一输入输出序列x2=b,状态s3的唯一输入输出序列x3=bbb,状态s4的唯一输入输出序列x4=bbb。同时,假设B具备重置能力,重置输入字符为r。则如下一组输入序列可以分别验证s1、s2、s3、s4在B中存在对应的相似状态:

{rbb, rbb, rabbb, rbbbbb}

如下一组输入序列可以验证各个迁移的正确性:

{rbb, rbbbbb, rbbabbb, rbbaab, rabbb, raab, rabbb, rbab, rbbbbbb}

合并这些输入序列中的重复或互相包含的部分,最终得到检查序列为:raabrabbbrbabrbbabbbrbbbbbb

8. 识别序列

为了验证B与A相似,我们需要针对A的每一个状态si,测试其划分集Zi中的每一个输入序列,确认B的输出是否与A相同。假定Zi中有两个输入序列z1和z2,那么我们就需要先让B进入某个状态si',然后给B输入z1,再让B回到si',最后给B输入z2。如果这个过程中B的输出都跟A相同,那么si'就与si相似。但问题是,如果B不能输出状态消息,也没有重置能力,甚至不存在区分序列,那么如何确保输入z1之后,B能回到si'呢?

这时候,我们还有一种办法,就是利用“识别序列”。

仍然以如图1所示状态机A为例:

图1

我们的目标是验证A的状态s1与B中某个状态相似。已知s1的划分集是{a, b}。设B的初始状态是q0,给B输入aaa,使B的状态依次迁移至q1、q2、q3,并且观察到对应输出为000。由于B最多只有3个不同的状态(一致性测试的基本假设),q0~q3中必然有两个状态是相同的,假设这两个状态是qi和qj(i≠3且j≠3)。因为B进入qi和qj之后收到的输入都是a,所以这两个状态各自的后继状态qi+1和qj+1也是相同的。以此类推,可知最后一个状态q3也必然与q0~q2中某个状态qk相同。既然当B处于qk状态时,输入a对应的输出是0,那么,在B处于q3状态时输入a,对应的输出也必然是0。因此,我们只需要测试当B处于q3状态时,给B输入b的情况。如果这时B的输出是1,我们就足以断定B的状态q3与A的状态s1相似。因此,aaab就是状态s1的识别序列。如果给B输入aaab对应的输出是0001,那么输入aaa之后B的状态就是与s1相似的状态s1’。

如果A有n个状态,状态si的划分集Zi={z1,z2},设t_i=\delta(s_i,z_1),则序列\left (z_1 \tau\left ( t_i,s_i \right ) \right )^n z_2是状态si的识别序列。

不失一般性,设A的状态si的划分集Z_i=\left \{ z_1,z_2,\cdots ,z_l \right \}t_{ir} =\delta(s_i,z_r)z'_r=z_r \tau(t_{ir},s_i),即是说,z'_r可以让A从si状态先迁移到t_{ir}状态,再回到si状态。定义如下输入序列:

\beta _r =\begin{cases} null & \text{ if } r=1 \\ \left (\beta_{r-1}z'_{r-1} \right )^n \beta_{r-1} & \text{ if } r>1 \end{cases}

则序列\beta_l z_l是状态si的识别序列。如果这个序列测试通过了,我们就可以断定,B在输入\beta _l之后进入的状态,与A的si状态是相似的。

设状态si的识别序列是I_i,且t_i=\delta(s_i,I_i),则如下序列可以验证B是否与A相似:

I_1 \tau (t_1,s_2)I_2 \tau (t_2,s_3)I_3\cdots I_n \tau (t_n,s_1) I_1

如何利用识别序列验证迁移的正确性呢?既然\beta _l可以确保让B进入与si相似的状态s'_i(在B的输出与A相符的前提下),那么对于迁移s_i \overset{a/0}{\rightarrow}s_j的验证,我们就可以先利用\beta _l让B进入s'_i,然后给B输入a,验证输出是否为0,继而使用s_j的划分集验证后继状态是否为s'_j

相关文章:

  • 制造业网络安全的挑战与应对策略
  • Electron截取响应体
  • 数字孪生系统汽车工厂生产异常监控的智能利器
  • JPA全面指南:使用步骤、语法详解与实战案例
  • 【Python办公】使用pandas批量读取csv保存为Excel
  • 产品哲学:用户收益>操作成本,字节跳动成功的底层逻辑
  • Golang 处理字符串与整型数值相互转换的最佳实践
  • 【备忘】PHP web项目一般部署办法
  • AI LLM大模型逆向环境搭建radare2 + r2mcp + r2ghidra
  • 【设计模式】UML图与工厂模式
  • 提升开发思维的设计模式(上)
  • spring:使用注解@Configuration、@ComponentScan创建配置类(未完待续)
  • C语言:字符函数
  • 基于ssm的教学质量评估系统
  • SQL Server判断中文的高效方法
  • 使用docker compose部署netmaker打通内网
  • 基于Springboot的动态刷新定时任务
  • 工业数据互联新基建:三格电子 PLC 数据采集网关破解跨协议通信难题
  • 高精度算法详解:从原理到加减乘除的完整实现
  • Jmeter本身耗资源导致压测不上去解决方案
  • 做pc端网站效果/湖南网站托管
  • 免费做宣传单页的网站/怎么做seo
  • 网站改版完成/快点tv下载安装
  • 深圳做生鲜食材的网站叫什么/自己有网站怎么推广
  • 中国被墙的网站/搜易网服务介绍
  • 小程序代理运营/seo关键词优化排名