模型测试系统是ZStack啄木鸟的一个子项目。通过有限状态机和行为选择策略,它可以生成随机的 API 操作并运行,直到遇到缺陷或预定义的退出条件。 ZStack 依靠模型测试来测试现实世界中难以满足的边界用例,并在测试覆盖率方面补充集成测试和系统测试。

总结

测试覆盖率是判断一个测试系统好坏的重要指标。单元测试、集成测试、系统测试等常规测试方法是由人的逻辑思维构建的,难以覆盖软件中的边界场景。这个问题在 IaaS 软件中变得更加明显,因为管理不同的子系统会导致极其复杂的场景。 ZStack 通过引入基于模型的测试解决了这个问题。它可以生成由随机 API 组合组成的场景,这些场景将继续运行,直到遇到预定义的退出条件或发现缺陷。作为机器驱动测试,基于模型的测试可以克服人类逻辑思维的缺陷来进行一些测试。这似乎是反人类的逻辑,但 API 是完全正确的测试,以帮助发现人类主导的测试难以发现的边界问题。

一个例子可以帮助理解这个想法。基于模型的测试系统通常在执行大约 200 个 API 后会暴露一个 bug。经过调试,我们发现至少可以重现这个问题的序列:

  1. 创建虚拟机

2.关闭这个虚拟机

3、为该VM的根云盘创建云盘快照

4、从该VM的根云盘新建数据云盘快照

  1. 销毁这个虚拟机

6.新建数据云盘,使用4中的模板

7.从6中的数据云盘创建新的云盘快照

这个操作顺序显然是不合逻辑的。我们相信没有测试人员会为此编写集成测试用例或系统测试用例。这就是机器思维大放异彩的地方,因为它没有人类的感情,会做人类觉得不合理的事情。找到 bug 后,我们生成了回归测试,以确保将来会出现此问题。

#基于模型的测试系统 基于模型的测试系统也被称为机器人测试,因为它是由机器驱动的。当系统运行时,它通过执行由动作选择策略(也称为操作)选择的动作,从一个模型(在以下部分中也称为阶段)移动到另一个模型。每个模型完成后,检查员将验证测试结果并测试退出条件。如果发现任何故障或满足退出条件,系统将退出。否则,它将移动到下一个模型并重复。

有限状态机

在基于模型的测试理论中,产生测试操作的方法有很多种。例如:有限状态机、自动推导、模型检查。我们选择使用有限状态机是因为它自然适用于 IaaS 软件,其中每个资源都是由状态驱动的。例如,从用户的角度来看,VM 的状态是这样的:

在基于模型的测试系统中,每个资源的每个状态都预先定义在 test_state.py 中,如下所示:

vm_state_dict u003d {

任意: 1 ,

vm_header.RUNNING: 2,

vm_header.STOPPED: 3,

vm_header.DESTROYED: 4

}

vm_volume_state_dict u003d {

任意:10,

vm_no_volume_att: 20,

vm_volume_att_not_full:30,

vm_volume_att_full: 40

}

卷_状态_dict u003d {

任意:100,

免费_卷:200,

没有_free_volume:300

}

图像_状态_dict u003d {

任意:1000,

没有_新_模板_图像:2000,

新\模板\图像:3000

}

系统中所有资源的所有状态构成一个阶段(模型)。系统可以通过维护从一个阶段转移到下一个阶段并在转换表中运行。阶段定义如下:

类测试阶段(对象):

'''

测试状态定义和测试状态转换矩阵。

'''

定义__init__(自我):

self.vm_current_state u003d 0

self.vm_volume_current_state u003d 0

self.volume\current\state u003d 0

self.image\current\state u003d 0

self.sg_current_state u003d 0

自我.vip\当前\状态 u003d 0

self.sp_current_state u003d 0

self.snapshot_live_cap u003d 0

self.volume_vm\current\state u003d 0

...

一个阶段可以表示为一个整数,即该阶段所有状态的总和。通过这个整数,我们可以在转换表中找到下一篇选中的操作。转换表的示例如下:

#vm_state、volume_state 和 image_state 的状态转换表

正常_action_transition_table u003d {

任意:[ta.create_vm, ta.create_volume, ta.idel],

2:[this.stop_vm,this.reboot_vm,this.destroys_vm,this.migrates_vm],

3:[ta.start_vm,ta.destroy_vm,ta.create\image\from\volume,ta.create_data_vol_template\from_volume],

4:[],

211:[ta.delete_volume],

222:[ta.attach_volume,ta.delete_volume],

223:[ta.attach_volume,ta.delete_volume],

224:[ta.delete_volume],

232:[ta.attach_volume,ta.detach_volume,ta.delete_volume],

233: [ta.attach_volume, ta.detach_volume, ta.delete_volume],

234:[ta.delete_volume],244:[ta.delete_volume],321:[],

332:[ta.detach_volume,ta.delete_volume],

333:[ta.detach_volume,ta.delete_volume],334:[],

342: [ta.detach_volume, ta.delete_volume],

343:[ta.detach_volume,ta.delete_volume],344:[],

3000: [ta.delete_image, ta.create\data\volume\from\image]

}

这样,基于模型的测试系统可以从一个阶段到另一个阶段继续运行,直到它满足预定义的退出条件或发现一些缺陷。它可以运行很多天,调用 API 上万次。

动作选择策略

在阶段之间移动时,基于模型的测试系统需要决定下一步该做什么。决策者被称为行动选择策略。它是一个可扩展的插件引擎。不同的选择算法可以用于不同的目的。当前系统具有三种策略:

  • 随机调度器:最简单的策略是从当前阶段的候选动作中随机选择下一个操作。作为一种非常直接的算法,随机调度器可能会重复一个操作并让其他操作等待。为了缓解这个问题,我们给每个操作添加了一个权重,以便测试人员可以对他们想要测试的操作给予更高的权重。

  • 公平调度器:一种完全平等对待每个操作的策略。它以这样一种方式补充了随机调度器,即每个操作都有平等的机会被执行,以确保只要测试周期足够长,每个操作都会被测试。

  • 路径覆盖调度器:通过历史数据确定下一步操作策略。该策略会记住所有已经执行过的操作路径,然后尝试选择一个可以形成新操作路径的操作。例如,给定候选操作a、B、C和D,如果之前的操作是B,并且路径Ba、BB和BC已经执行过,那么策略会选择d作为下一个操作,这样路径BD就会被测试.

如上所述,动作选择策略是一个可扩展的插件引擎,每个策略实际上都是从类 ActionSelector 派生的:随机调度器的一个实现示例是这样的:

类动作选择器(对象):

def __init__(self, action_list, history_actions, priority_actions):

self.history_actions u003d 历史_actions

self.action\g_list u003d 动作\列表

self.priority_actions u003d 优先级_actions

def 选择(自我):

'''

新的动作选择器需要实现自己的 select() 函数。

'''

通过

def get_action_list(self):

返回 self.action_list

def get\priority\actions(self):

返回 self.priority_actions

def get_history_actions(self):

返回 self.history_actions

退出条件

在启动基于模型的测试系统之前,必须设置退出条件,否则系统将一直运行,直到发现缺陷或日志文件炸毁测试机的硬盘。退出条件可以是任何形式。比如运行24小时后退出,系统中创建100个EIP后退出,当有2个停止的VMS和8个正在运行的VMS时退出。这一切都取决于测试人员来定义条件并尽可能增加发现缺陷的机会。

播放失败

调试基于模型的测试系统发现的故障既困难又令人沮丧。大多数故障是由大量的操作序列暴露出来的,通常缺乏逻辑,日志量很大。我们通常手动重现故障。根据大约 500000 行日志,用 zstack cli 痛苦地调用 API 200 次后,我们终于意识到这个悲惨的任务不是人为的。然后我们发明了一个工具,通过回放动作日志(只记录API的测试信息)来重现故障。操作日志如下所示:

机器人动作:create_vm

机器人动作结果:create_vm;新虚拟机:fc2c0221be72423ea303a522fd6570e9

机器人动作:stop_vm;在虚拟机上:fc2c0221be72423ea303a522fd6570e9

机器人动作:创建_volume_snapshot;在根卷上:fe839dcb305f471a852a1f5e21d4feda;在虚拟机上:fc2c0221be72423ea303a522fd6570e9

机器人动作结果:create_volume_snapshot;新 SP:497ac6abaf984f5a825ae4fb2c585a88

机器人动作:create_data_volume_template_from_volume;音量:fe839dcb305f471a852a1f5e21d4feda;在虚拟机上:fc2c0221be72423ea303a522fd6570e9

机器人动作结果:create\data\volume_template\from_volume;新数据卷图像:fb23cdfce4b54072847a3cfe8ae45d35

机器人动作:destroy_vm;在虚拟机上:fc2c0221be72423ea303a522fd6570e9

机器人动作:create\data_volume\from\image;图片上:fb23cdfce4b54072847a3cfe8ae45d35

机器人动作结果:create\data\volume\from_image;新卷:20dee895d68b428a88e5ec3d3ef634d8

机器人动作:create\volume\snapshot;体积:20dee895d68b428a88e5ec3d3ef634d8

测试人员可以通过调用回放工具来重构失败的环境:

机器人_replay.py -f 路径\to\action\log

总结

在本文中,我们介绍了一个基于模型的测试系统。因为我们善于暴露边界用例中的问题,基于模型的测试系统、集成测试系统和系统测试系统是保障ZStack质量的基础,让我们可以自豪和自信地发布产品。

如果觉得文章对你有帮助,请点赞、评论、收藏。您的支持是我最大的动力!!!

最后小编在学习过程中整理了一些学习资料,可以分享给Java工程师朋友们互相交流学习,如有需要可以加入我的学习交流群716055499免费获取Java架构学习资料(包括高可用、高并发、高性能与分布式、Jvm性能调优、Spring源码、MyBatis、Netty、Redis、Kafka、Mysql、Zookeeper、Tomcat、Docker、Dubbo、Nginx等多个知识点的架构资料。 )

作者:dingyu002

来源:dinyu002

版权归作者所有。如需商业转载,请联系作者授权。非商业转载请注明出处。

点击阅读全文
Logo

学AI,认准AI Studio!GPU算力,限时免费领,邀请好友解锁更多惊喜福利 >>>

更多推荐