You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

237 lines
17 KiB
Markdown

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 23设计实战: 一个分布式多端视频会议自动化测试设计
你好,我是柳胜。
这几年疫情肆虐全球,远程办公越来越普遍了,视频会议的市场也变得更加火热。视频会议软件的质量,自然也需要测试保驾护航。
不过,视频会议软件自动化测试非常有挑战性,因为它有很多难点:第一,协作复杂;第二,分布式执行;第三,验证有技术难度。
今天,我们就来为视频会议软件设计一套自动化测试方案,用来测试视频会议的会议功能。
## 场景还原
我们先从视频会议的时序图开始分析你就明白视频会议的自动化测试有多复杂了。这里我选择了一个迷你demo但麻雀虽小五脏俱全。假定会议用户有三位使用Web端的用户A、桌面用户B以及手机用户C。
![图片](https://static001.geekbang.org/resource/image/71/23/71253a39b0e2dec88835edf5efcaee23.jpg?wh=1920x1192)
如图所示Web用户A先在浏览器创建一个Meeting发送邀请链接给桌面用户B和手机用户C然后B和C加入会议A、B、C三个人同时在线。
这时用户A开始演示自己的屏幕B和C要收到A演示的屏幕A如果在聊天区里发送一个消息B和C也要收到这个消息。
这样一个复杂的场景,我们既要测试视频会议的分布式协作能力,还要测试会议的准确度,另外还要保证效率性能。这三方面的测试目标,我用表格的方式来举例说明,你可以看看。
![图片](https://static001.geekbang.org/resource/image/64/5c/644a891248a8a9ba0f5b0c8ac0d6c55c.jpg?wh=1920x691)
## 视频会议测试概要设计
那么,自动化测试该怎么设计和实现,才能达到上面的目标?我们先从概要设计开始分析。
还是遵循从顶向下的设计思路,我们先捋出来要完成视频会议测试,需要测试哪几个功能区。
首先是初始化,初始化的过程,是保证所有的客户端都进入到视频会议里;然后测试演示功能区,也就是完成一个客户端演示,其它客户端观看演示的过程;接着要测试聊天功能区,一个客户端发送聊天,其它客户端接收聊天;最后是退出,测试完毕后,各个客户端依次退出视频会议系统。
根据这个思路我们先把视频会议Job切分成4个子Job如下图所示
![图片](https://static001.geekbang.org/resource/image/fb/68/fbc44e98d4aa9d6bb6a04b72e04e4168.jpg?wh=1920x905)
**4个功能首尾衔接按照依赖关系和重要程度权值高的排在前面。**如果权值高的失败了后续的Job就没有必要运行了。根据Job模型层级原则如果有任何一个子Job失败了视频会议自动化Job就会失败。
为了支持分布式我们还需要在Job模型里加入一个host属性指明本Job运行的主机环境。
像这样host=“10.0.0.1”就代表着本Job会被发送到10.0.0.1这台机子上去运行。
![图片](https://static001.geekbang.org/resource/image/20/8b/201b3d53eb2ee00136a97839d7ff268b.jpg?wh=1920x1113)
有了这个属性后,后面我们就好建模了。接下来,我们依次来看各个功能区怎么设计。
## 初始化功能设计
初始化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。
![图片](https://static001.geekbang.org/resource/image/bf/45/bf5545c0344834010348a8cc13b31b45.jpg?wh=1920x1215)
但有一个问题初始化Job的运行结果是ABC都加入了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也就没必要再去执行了。
![图片](https://static001.geekbang.org/resource/image/a9/c0/a9b000199746d04dbb650fd8eaf87ac0.jpg?wh=1920x1627)
这种设计的好处是,**整体自动化测试的健壮性很强**。按照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 JobVerifyJoin和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就可以完成这个任务了。
![图片](https://static001.geekbang.org/resource/image/06/2d/065dca1d511b6fd0895bca85141d7f2d.jpg?wh=1920x1215)
但是,相比“初始化功能”,“演示功能”有两个特殊的地方需要考虑,一个是屏幕相似度,另一个是屏幕切换的流畅度。
### 屏幕相似度
如何验证演示的正确性当A展示一张PPT的时候怎么让程序验证B和C看到的和A演示的是一样的PPT呢
比如出现这样的屏幕是正常的。
![图片](https://static001.geekbang.org/resource/image/c2/91/c277d037916ab6e87f3dae90a5450591.jpg?wh=1920x626)
但下面这样C端出了问题没有完整显示下半部分有一块黑色区域。
![图片](https://static001.geekbang.org/resource/image/97/07/971c136b2c75d8188a13e19832f1a907.jpg?wh=1920x617)
看到这里你可能已经想到了视频会议的屏幕演示其实就是一帧帧的图片我们可以采用位图比较的思路来验证ABC所看到的屏幕是不是一致。
怎么实现位图比较呢?如果自开发的话,可以自己去写图像比较的算法,来计算两张图片之间的相似度。我给你列了一个表,里面提炼了几个经典算法的原理和优缺点。
![图片](https://static001.geekbang.org/resource/image/e8/5e/e856ab2fd7df1fc67b03de02c765655e.jpg?wh=1920x704)
从上表可以看到,不同的算法,都有各自的优缺点和适用场景。而且,开发和维护这些算法的代码,也是一个不小的工作量。
那有没有智能对比图片的办法呢图片识别和比较是AI擅长的领域它们应用到测试领域就是AI测试。业界有两个比较成熟的两个AI测试工具Applitools和Sikuli。
Applitools 是一个AI 赋能的测试工具通过视觉AI 进行智能功能和视觉测试。具体怎么实现呢?
A端先把自己的屏幕抓屏保存成图片上传到Applitools服务器形成一个**基线**。B和C也把自己的屏幕图片上传到同样的**基线**Applitools会自动对同一基线的图片对比得出结果。A、B、C端执行的代码如下
```java
//创建基线 "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经过对比是一致的所以结果为成功。
![图片](https://static001.geekbang.org/resource/image/18/a7/180f813b1f260b70d311d928cbc362a7.jpg?wh=1920x1023)
在图片上还有两个图标点赞和消赞分别对应着Accept Diff和Reject Diff。当Applitools发现图片不匹配时比如在图片中有动态的值日期时间用户名等等每次运行的值都不一样你可以通过点击这点赞的图标Accept Diff来反馈训练Applitools的图片识别算法反馈次数越多训练出的识别能力越精准。
Applitools很好用但有一个限制它需要图片上传到Applitool自己的官方服务器进行识别。如果我们对数据有安全的顾虑Sikuli更适合。Sikuli由美国麻省理工学院研究开发是一款基于视觉的测试工具也提供了图片比较函数代码示例如下
```java
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的时间。
![图片](https://static001.geekbang.org/resource/image/07/9d/07bb7223c7d2dc9d3a6c240fc78b1a9d.jpg?wh=1920x620)
聊天功能和演示功能类似由A发送一个MessageB和C都要接收它。这里也有准确性和时效性的问题。解决方案和演示功能相似你可以自己梳理一下Job树巩固前面学到的内容。
## 实现与扩展
到这里我们把刚才的设计整理一下整体成果Job树如下
![图片](https://static001.geekbang.org/resource/image/88/b1/88cde599cfcd1c26af0ed42cb768d9b1.jpg?wh=1920x890)
从图里可以看到我们一共用15个Job完成了这个视频会议自动化测试场景的设计。接下来我们对照Job树继续推演需要实现的子Job和适合的工具。
### 实现
所有的叶子结点Job都是后面测试实现阶段中测试开发同学需要开发实现的实体Job把它列成一个Job树叶子工作表
![图片](https://static001.geekbang.org/resource/image/c8/2f/c8fe5e9563fyy279266940e722d4f52f.jpg?wh=1920x839)
然后就到了每个Job选型工具的确定。工具的列表可以参考我为本专栏准备的 [Gitub地址](https://github.com/atinfo/awesome-test-automation/blob/master/java-test-automation.md)。选型遵循3KU法则寻找合适的测试层面和成熟的工具。
![图片](https://static001.geekbang.org/resource/image/ae/af/ae158cca355d8f23f0989c3455dd67af.jpg?wh=1920x824)
### 扩展
在刚才的Job设计中视频会议的Desktop端是Windows所以JoinMeetingDesktop Job的实现用WinAppDriver。
如果未来有一天我们的视频会议有了Mac端这个时候Job设计怎么变化
我们可以想一下不论是Mac还是Windows、Linux它们都只是视频会议的不同载体但上面实现的业务是一样的。也就是说我们上面基于业务做的Job设计依然有效。
这时可以把JoinMeetingDesktop变成抽象Job增加3个子JobJoinMeetingWindows、JoinMeetingMac、JoinMeetingLinux它们是对JoinMeetingDesktop的实现。当JoinMeetingDesktop运行的时候会把子Job都运行一遍Windows、Linux、Mac就都得到了测试验证。
![图片](https://static001.geekbang.org/resource/image/1a/7e/1a01495793cf2a01b5ee4057bc93937e.jpg?wh=1920x1300)
## 小结
今天我们通过视频会议的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模型来完成各种自动化测试设计。