【ZStack】自动测试系统3——基于模型的测试
模型测试系统是ZStack啄木鸟的一个子项目。通过有限状态机和行为选择策略,它可以生成随机的 API 操作并运行,直到遇到缺陷或预定义的退出条件。 ZStack 依靠模型测试来测试现实世界中难以满足的边界用例,并在测试覆盖率方面补充集成测试和系统测试。 总结 测试覆盖率是判断一个测试系统好坏的重要指标。单元测试、集成测试、系统测试等常规测试方法是由人的逻辑思维构建的,难以覆盖软件中的边界场景。这个
模型测试系统是ZStack啄木鸟的一个子项目。通过有限状态机和行为选择策略,它可以生成随机的 API 操作并运行,直到遇到缺陷或预定义的退出条件。 ZStack 依靠模型测试来测试现实世界中难以满足的边界用例,并在测试覆盖率方面补充集成测试和系统测试。
总结
测试覆盖率是判断一个测试系统好坏的重要指标。单元测试、集成测试、系统测试等常规测试方法是由人的逻辑思维构建的,难以覆盖软件中的边界场景。这个问题在 IaaS 软件中变得更加明显,因为管理不同的子系统会导致极其复杂的场景。 ZStack 通过引入基于模型的测试解决了这个问题。它可以生成由随机 API 组合组成的场景,这些场景将继续运行,直到遇到预定义的退出条件或发现缺陷。作为机器驱动测试,基于模型的测试可以克服人类逻辑思维的缺陷来进行一些测试。这似乎是反人类的逻辑,但 API 是完全正确的测试,以帮助发现人类主导的测试难以发现的边界问题。
一个例子可以帮助理解这个想法。基于模型的测试系统通常在执行大约 200 个 API 后会暴露一个 bug。经过调试,我们发现至少可以重现这个问题的序列:
- 创建虚拟机
2.关闭这个虚拟机
3、为该VM的根云盘创建云盘快照
4、从该VM的根云盘新建数据云盘快照
- 销毁这个虚拟机
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
版权归作者所有。如需商业转载,请联系作者授权。非商业转载请注明出处。
更多推荐
所有评论(0)