23 设计实战(三): 一个分布式多端视频会议自动化测试设计
你好,我是柳胜。
这几年疫情肆虐全球,远程办公越来越普遍了,视频会议的市场也变得更加火热。视频会议软件的质量,自然也需要测试保驾护航。
不过,视频会议软件自动化测试非常有挑战性,因为它有很多难点:第一,协作复杂;第二,分布式执行;第三,验证有技术难度。
今天,我们就来为视频会议软件设计一套自动化测试方案,用来测试视频会议的会议功能。
场景还原
我们先从视频会议的时序图开始分析,你就明白视频会议的自动化测试有多复杂了。这里我选择了一个迷你demo,但麻雀虽小,五脏俱全。假定会议用户有三位:使用Web端的用户A、桌面用户B,以及手机用户C。
如图所示,Web用户A先在浏览器创建一个Meeting,发送邀请链接给桌面用户B和手机用户C,然后B和C加入会议,A、B、C三个人同时在线。
这时,用户A开始演示自己的屏幕,B和C要收到A演示的屏幕;A如果在聊天区里发送一个消息,B和C也要收到这个消息。
这样一个复杂的场景,我们既要测试视频会议的分布式协作能力,还要测试会议的准确度,另外还要保证效率性能。这三方面的测试目标,我用表格的方式来举例说明,你可以看看。
视频会议测试概要设计
那么,自动化测试该怎么设计和实现,才能达到上面的目标?我们先从概要设计开始分析。
还是遵循从顶向下的设计思路,我们先捋出来要完成视频会议测试,需要测试哪几个功能区。
首先是初始化,初始化的过程,是保证所有的客户端都进入到视频会议里;然后测试演示功能区,也就是完成一个客户端演示,其它客户端观看演示的过程;接着要测试聊天功能区,一个客户端发送聊天,其它客户端接收聊天;最后是退出,测试完毕后,各个客户端依次退出视频会议系统。
根据这个思路,我们先把视频会议Job切分成4个子Job,如下图所示:
4个功能首尾衔接,按照依赖关系和重要程度,权值高的排在前面。如果权值高的失败了,后续的Job就没有必要运行了。根据Job模型层级原则,如果有任何一个子Job失败了,视频会议自动化Job就会失败。
为了支持分布式,我们还需要在Job模型里加入一个host属性,指明本Job运行的主机环境。
像这样,host=“10.0.0.1”,就代表着本Job会被发送到10.0.0.1这台机子上去运行。
有了这个属性后,后面我们就好建模了。接下来,我们依次来看各个功能区怎么设计。
初始化功能设计
初始化Job,要完成的任务是A、B、C进入会议,同时在线。怎么设计呢?
我们还是先按操作顺序梳理一下A、B、C都做了什么。
首先,A要做一个CreateMeeting的操作,把它发到10.0.0.1主机上运行,输出一个MeetingUrl;然后,B和C从Input里取到MeetingUrl,在10.0.0.2主机上执行JoinMeetingDesktop,在10.0.0.3主机上执行JoinMeetingAndroid的Job。
但有一个问题,初始化Job的运行结果是,A,B,C都加入了Meeting。怎么验证A、B和C都加入到会议里了呢?又由谁去做这个验证呢?
可以这样设计,等A、B、C都执行完操作以后,再运行一个VerifyJoin的Job,来验证ABC是否都已经成功加入Meeting了。
在Job树上会有这样的结构:把A、B、C聚合成一个ScheduleMeeting的Job,然后VerifyJoinJob的Dependency指向ScheduleMeeting Job。
在执行的时候,等到ScheduleMeeting Job执行完且结果为通过的情况下,VerifyJob会才会开始执行。如果A、B、C其中有一个失败了,ScheduleMeeting就会失败,VerifyJoin的Job也就没必要再去执行了。
这种设计的好处是,整体自动化测试的健壮性很强。按照Job树的运行原理,运行顺序是这样的:CreateMeeting先运行,然后是JoinMeetingDesktop和JoinMeetingAndroid,最后再运行VerifyJoin。任何一个失败,后面都不必运行了。
不过,这种设计也有一个问题,就是自动化测试运行的效率。VerifyJoin的要等到ScheduleMeeting Job全部执行完了,才能执行,整个自动化测试任务执行时间是这4个Job执行时间的总和。
time(Total)=time(CreateMeeting)+time(JoinMeetingDesktop)+time(JoinMeetingAndroid)+time(VerifyJoin)
假设CreateMeeting花了30秒,JoinMeetingDesktop花了20秒,JoinMeetingAndroid花了25秒,VerifyJoin花了15秒。那根据这个公式,总共执行时间是 30+20+25+15 = 90秒,总共一分半的时间。
优化执行时间
怎么让执行时间缩短呢?面对这个问题,你可能会想到,有没有办法把串行执行变成并发执行呢?这样时间就缩短了。
没错,对于Job树上同一层级且没有依赖关系的子Job们,谁先执行、谁后执行都无所谓。为了加快执行速度,我们可以优化JobRunner的机制,用并发线程执行它们。
沿着这个思路,我们可以解除一些依赖关系,让执行效率得到提升,让VerifyJoin Job不再依赖于ScheduleMeeting Job,VerifyJoin和ScheduleMeeting同时启动。
VerifyJoinJob并不知道ScheduleMeeting是否开始,何时结束,它就是不停地轮询A、B、C是否都加入Meeting,如果得到确认就返回,否则会直到超时报错。没错,这里我们可以用上Job模型的TestConfig里的TimeOut参数,比如,我们给VerifyJoinJob设置TimeOut参数是3分钟。
在这个方案下,我们再算一下执行时间是多少。ScheduleMeeting的执行时间的计算公式如下:
executeTime(ScheduleMeeting)=executeTime(CreateMeeting)+ Max(executeTime(JoinMeetingDesktop), executeTime(JoinMeetingAndroid))30+Max(25,20)=55秒
而VerifyJoin Job是和ScheduleMeeting是并发执行的,只要ScheduleMeeting成功运行,ABC同时上线,VerifyJoin Job就会立即成功返回。
所以,和上面同样的Job,现在优化了JobRunner后,整个自动化测试的任务执行时间就缩短到了55秒。相比优化之前的90秒,自动化测试的运行速度加快了40%。
而且,健壮性也得到了保证,即使有错误发生,也不会超过3分钟。根据上面的描述,你可以脑补一下相应的Job树还有它的时间计算公式。
演示功能设计
演示功能又是一个需要多端协作的场景。这是个什么场景呢?简单来说,A开始演示PPT的时候,B和C都要能看到这张PPT。
我们可以用“初始化功能设计”的思路,来完成这个设计,A要执行presentPPT的Job,然后在B和C上分别执行viewPPT的Job,就可以完成这个任务了。
但是,相比“初始化功能”,“演示功能”有两个特殊的地方需要考虑,一个是屏幕相似度,另一个是屏幕切换的流畅度。
屏幕相似度
如何验证演示的正确性?当A展示一张PPT的时候,怎么让程序验证,B和C看到的和A演示的是一样的PPT呢?
比如出现这样的屏幕是正常的。
但下面这样,C端出了问题,没有完整显示,下半部分有一块黑色区域。
看到这里,你可能已经想到了,视频会议的屏幕演示,其实就是一帧帧的图片,我们可以采用位图比较的思路,来验证A,B,C所看到的屏幕是不是一致。
怎么实现位图比较呢?如果自开发的话,可以自己去写图像比较的算法,来计算两张图片之间的相似度。我给你列了一个表,里面提炼了几个经典算法的原理和优缺点。
从上表可以看到,不同的算法,都有各自的优缺点和适用场景。而且,开发和维护这些算法的代码,也是一个不小的工作量。
那有没有智能对比图片的办法呢?图片识别和比较是AI擅长的领域,它们应用到测试领域就是AI测试。业界有两个比较成熟的两个AI测试工具,Applitools和Sikuli。
Applitools 是一个AI 赋能的测试工具,通过视觉AI 进行智能功能和视觉测试。具体怎么实现呢?
A端先把自己的屏幕抓屏,保存成图片上传到Applitools服务器,形成一个基线。B和C也把自己的屏幕图片上传到同样的基线,Applitools会自动对同一基线的图片对比,得出结果。A、B、C端执行的代码如下:
//创建基线 "Image-PresentScreen1"
eyes.open("Video Meeting", "Image-PresentScreen1 ", new RectangleSize(800, 600));
//对屏幕抓图
File file = Screen.capture();
BufferedImage img = ImageIO.read(file);
eyes.check("Image buffer", Target.image(img));
//关闭Eyes.
eyes.close();
在Applitools的网站可以看到三条成功的记录,A和B和C上传的图片,Applitools经过对比是一致的,所以结果为成功。
在图片上,还有两个图标,点赞和消赞,分别对应着Accept Diff和Reject Diff。当Applitools发现图片不匹配时,比如在图片中有动态的值(日期,时间,用户名等等),每次运行的值都不一样,你可以通过点击这点赞的图标Accept Diff,来反馈训练Applitools的图片识别算法,反馈次数越多,训练出的识别能力越精准。
Applitools很好用,但有一个限制,它需要图片上传到Applitool自己的官方服务器进行识别。如果我们对数据有安全的顾虑,Sikuli更适合。Sikuli由美国麻省理工学院研究开发,是一款基于视觉的测试工具,也提供了图片比较函数,代码示例如下:
Screen screen=new Screen();
Pattern pa1=new Pattern("/Users/37397/Desktop/Screen Shot 2018-03-27 at 6.02.42 PM.png");
String img=screen.capture().save("/Users/1234/Desktop/Automation/Test_Sikuli/", "image");
Finder f1=new Finder(screen.capture().getImage());
f1.find(pa1);
if(f1.hasNext()){
Match m=f1.next();
System.out.println("Match found with "+(m.getScore())+"100"+"%");
f1.destroy();
}
else{
System.out.println("No Match Found");
}
屏幕切换流畅度
演示的流畅也是需要测试的。怎么度量演示的流畅?我们可以用延迟时间来评价。也就是当A切换屏幕之后,B和C上的画面也开始切换,这个时间差就是延迟时间。
现在的问题就变成了——怎么来截取这个时间差?这就涉及到一个分布式事务的概念,如果我们定义的Transaction是timeBetweenPresentAndView,那么Transaction Start是在A端开始Present的时候,而Transaction End是在B端看到PPT的时候。
分布式事务怎么实现?在Job模型里,我们可以用Input和Output来实现。A的Job在Present之后就立刻记录下当前的时间戳,输出一个TR_START_timeBetweenPresentAndView=1342629206455,而B的Job在看到PPT之后,也立刻记录下时间戳,输出一个TR_END_timeBetweenPresentAndView=1342629276772。
那它们怎么聚合成最后的事务呢?这时候,我们可以创建一个aggreateTransaction的Job,专门负责从Input里拿到这些数据,然后计算输出TR_timeBetweenPresentAndView的时间。
聊天功能和演示功能类似,由A发送一个Message,B和C都要接收它。这里也有准确性和时效性的问题。解决方案和演示功能相似,你可以自己梳理一下Job树,巩固前面学到的内容。
实现与扩展
到这里,我们把刚才的设计整理一下,整体成果Job树如下:
从图里可以看到,我们一共用15个Job完成了这个视频会议自动化测试场景的设计。接下来,我们对照Job树,继续推演需要实现的子Job和适合的工具。
实现
所有的叶子结点Job,都是后面测试实现阶段中,测试开发同学需要开发实现的实体Job,把它列成一个Job树叶子工作表:
然后就到了每个Job选型工具的确定。工具的列表可以参考我为本专栏准备的 Gitub地址。选型遵循3KU法则,寻找合适的测试层面和成熟的工具。
扩展
在刚才的Job设计中,视频会议的Desktop端是Windows,所以JoinMeetingDesktop Job的实现用WinAppDriver。
如果未来有一天,我们的视频会议有了Mac端,这个时候Job设计怎么变化?
我们可以想一下,不论是Mac还是Windows、Linux,它们都只是视频会议的不同载体,但上面实现的业务是一样的。也就是说,我们上面基于业务做的Job设计依然有效。
这时,可以把JoinMeetingDesktop变成抽象Job,增加3个子Job:JoinMeetingWindows、JoinMeetingMac、JoinMeetingLinux,它们是对JoinMeetingDesktop的实现。当JoinMeetingDesktop运行的时候,会把子Job都运行一遍,Windows、Linux、Mac就都得到了测试验证。
小结
今天我们通过视频会议的Job设计,把一个分布式多端协作的交互场景,分解成一个个简单可开发任务,并且分析了子任务的Input和Output。其实,这个分解过程就是我们的自动化测试设计要做的工作。不难发现,用好我们的Job模型,这个分解工作就能迎刃而解了。
不过,之前我们的Job模型不支持分布式,所以,我们对Job模型又做了扩展,增加了Host属性,支持分派Job到不同的主机上运行。在Host属性可以增加多台主机名,那么就可以实现一个Job发送到多台机子上运行。
还是按照Job设计的思路,我们分而治之,把视频会议自动化的整个任务分解成了四个功能区:初始化Meeting,演示功能区,聊天功能区和退出Meeting。然后,我们再对每个功能下钻细化,直到可执行的实例Job。
视频会议自动化测试中,还会涉及一些具体的技术实现,比如图像比较,自开发算法和使用主流工具两种思路,我都为你做了简要分析。
自开发算法的问题是,开发打磨出一个可用的图像相似度算法会耗费人力,说白了就是投产比并不划算。
所以,我们可以借鉴业界已有的技术,比较成熟的两款工具是Applitools和Sikuli。我用一个例子来介绍Applitools AI识别图像的实现思路,你也可以把它应用在你的工作中去。
在设计过程中,我们也发现了执行效率可优化的空间。没有依赖关系的Job们,我们可以通过并发线程来执行它们,只有当存在依赖关系时,才需要顺序执行。通过这样一个机制上的优化,我们就能把视频会议自动化的执行时间缩短将近一半。
到这里,基于Job模型的自动化测试设计思路和案例就讲完了,相信你收获了一种全新的设计思路和实现方法。但在收获的同时,关于怎么落地,你一定还会有不少疑问,我完全能够理解。
一个新的设计方法,需要很多配套的实现。比如,围绕着OpenAPI设计就有一个工具生态圈:有OpenAPI规范来书写接口文档,有Swagger来可视化展现接口,有OpenAPI generator来自动生成代码。下一讲,我们就一起学习一下基于Job模型的框架实现和代码例子,敬请期待。
思考题
今天讲的视频会议的自动化测试场景设计,你觉得还有没有什么重要功能,是我们没有进行测试设计的?怎么用Job模型来完成这个功能呢?
欢迎你在留言区和我交流互动,也推荐你把今天学的内容分享给更多同事、朋友,一起应用Job模型来完成各种自动化测试设计。
- 羊羊 👍(3) 💬(1)
以前从事测试机顶盒中间件工作,有些视频质量验证的问题一直没有解决,希望老师能提供一些先进经验。例如: 音视频的同步检测; 视频的卡顿,马赛克; 视频显示在不同大小屏幕上的结果比对;
2022-08-02 - 羊羊 👍(1) 💬(1)
是否可以吧六边形模型中的host,抽象为设备信息,host属于设备的一个配置,检测阶段可能还会使用到其他设备的属性,例如屏幕尺寸,硬件性能,网络环境等。wifi和4G的延迟要求是不是也会不同? 在多设备测试中,不同终端的行为和检测,有些事相同的,有些是特定平台特有的。想请教一下老师,你们是如何实现的?每种终端一套独立的行为和检测代码?还是把相同的行为抽象为abstract class?
2022-08-03 - ifelse 👍(0) 💬(0)
学习打卡
2024-02-27