悠悠小仙仙 发表于 2017-6-22 14:44:49

测试开发之路--分布式用例执行

前言这两天趁着有时间,我疯狂的码字了~~
背景我们公司是做人工智能平台的,什么是人工智能呢? 大数据+机器学习。大数据运行的基本就不快。机器学习算法运行起来也是慢的让人泪流满面。在我们的集群配置下,我使用一个5M的数据从数据引入到数据处理,特征工程,模型训练和评估报告等等一整套线下模型调研流程要10分钟左右。所以单线程执行测试用例是不靠谱的。而UI自动化在一台机器上只能是单线程执行。所以多台机器同时运行case的分布式处理方案呼之欲出。
原理原理其实很简单。 我分步骤说一下

[*]我们是用jenkins做CI工具的。所以通过jenkins的slave机制添加多台slave机器当做测试机。配置测试机在同一时间只能运行一个任务,也就是不能并发执行。
[*]创建一个可以并发的job然后把步骤一中的测试机注册到这个job中,我们姑且叫这个job为run job。run job在触发构建的时候在所有的测试机中查询空闲的测试机,如果有空闲的就到这台机器上执行测试任务。如果没有空闲的机器就等待直到有机器空闲。
[*]我们把测试用例分成不同的group,然后创建一个分发任务的job,我们姑且叫这个job为dispatch job。dispatch job中配置一段shell脚本,通过jenkins API的方式调用run job并把group作为参数传递过去。这样我们在dispatch job中调用了N次run job 也就是在不同的机器上同时跑不同的group。
[*]接下来我们要解决测试报告的问题。我要创建一个归集所有测试结果的job,我们姑且叫它为results job。results job会拉取所有run job的测试结果并保存到特定位置
[*]然后我们创建一个merge测试结果并生成测试报告的job,我们姑且叫它为report job。
总结一下我们需要多台测试机器和4个job。分别是dispatch job,run job,results job和report job。 大概的样子如下:

https://testerhome.com/uploads/photo/2016/7c309273947171a07cb169173ad7b030.png%21large


配置slave 测试机这个比较简单,大家可以到网上找详细的教程。只需要记得创建的node要统一一个label比较好管理。如下:

https://testerhome.com/uploads/photo/2016/571e68302ee83811d32baaaee2621929.png%21large


dispatch job这个job基本就是由shell脚本构成的,通过shell来调用jenkins的API。如下:
#!/bin/sh

#输出构建者的信息
echo $BUILD_USER_EMAIL $BUILD_USER > tigger_user_info

#检查是否有任务还在跑
STATUS=`curl -v --silent "http://jenkins.4paradigm.com/job/prophet-test-run/api/json?tree=builds\" 2>&1 | grep -o "{\"result\":null}"`

#测试任务URL
RUN_JOB_URL="http://jenkins.4paradigm.com/job/prophet-test-run/buildWithParameters?token=prophet"

if [ "$STATUS" = "" ]; then
curl "$RUN_JOB_URL&env=$env&branch=$branch&group=atomTest.xml"
curl "$RUN_JOB_URL&env=$env&branch=$branch&group=model_train.xml"
curl "$RUN_JOB_URL&env=$env&branch=$branch&group=dataload.xml"
curl "$RUN_JOB_URL&env=$env&branch=$branch&group=smoke.xml"
printf "下发测试任务成功!\n"
else
printf "测试服务器繁忙,下发测试任务失败!\n"
exit -1
fi

#任务下发成功后删除上次构建产生的结果
rm -rf../../prophet-send-report/workspace/allure-results/*逻辑比较简单,首先检查当前还有没有run job在执行,如果有,那么执行失败。其实应该等待的执行结束的,只是暂时还没加这段逻辑。如果没有run job在执行。那么调用run job的API 把测试任务分发下去。其中要把一些参数传递过去。例如运行环境,测试代码分支,测试用例的group
run job这个job比较常规,配置有点多我不详细的列举了。无非就是配置git lab,拉取测试代码并build 运行测试。其中slave测试机是注册在这个job里的。有一个需要注意的地方是run job运行结束后触发下一个results job,需要传递一个比较重要的参数-- build number。因为下一个job 需要知道run job的build number好去归集测试结果。如下:

https://testerhome.com/uploads/photo/2016/b2db375feed09873e6ff7224b17c68ef.png%21large


对了还有一个特别重要的东西。为了要把测试结果从slave测试机上拉到jenkins上。我们需要剑走偏锋。配置如下:

https://testerhome.com/uploads/photo/2016/f6cc133677e21547e1091c2f5e852982.png%21large


其实这个时候我们并不希望在run job上就生成html 的report,我们指向的目录也不是report的目录。而是存放测试结果的xml文件的目录。jenkins默认是不会从slave测试机上拉取这些文件的。为了让jenkins拉取这些文件,所以我们利用这个html report插件强行让jenkins把他们拉取上来。
results job这也是一个有shell 构成的job。脚本如下:
#!/bin/sh

sleep 5s
# 通过run job传递的build number 将测试结果保存到特定目录下
folder="../../prophet-test-run/builds/$upstream_build/htmlreports/HTML_Report"
if [ -d "$folder" ]; then
cp -r "$folder" ../../prophet-send-report/workspace/allure-results/$upstream_build
fi


#获取测试执行Job里是否有未完成的任务
STATUS=`curl -v --silent "http://jenkins.4paradigm.com/job/prophet-test-run/api/json?tree=builds\" 2>&1 | grep -o "{\"result\":null}"`

if [ "$STATUS" = "" ]; then

#获取构建人信息
user_email=`awk '{print $1}' ../../prophet-task-dispatch/workspace/tigger_user_info`
user_name=`awk '{print $2}' ../../prophet-task-dispatch/workspace/tigger_user_info`

#邮件任务URL
EMAIL_JOB_URL="http://jenkins.4paradigm.com/job/prophet-send-report/buildWithParameters?token=report"

#触发发送报告任务
curl "$EMAIL_JOB_URL&user_email=$user_email&user_name=$user_name"
printf "下发邮件发送任务!\n"
else
printf "还有测试任务正在执行!\n"
fi逻辑也十分简单,根据run job传递build number,copy测试结果到特定的目录。 这里简单说明一下jenkins的目录结构。每个job都是存放在一个叫jobs的目录下,job目录里面有builds和workspace两个文件夹。builds目录分别存放每一个build的执行结果,results job 就是跑去run job的builds目录copy执行结果到reports 的workspace目录下(run job传递过来的build number起作用了). workspace 目录就是jenkins上看到的工作控件了。我们shell就是在这个目录下运行的。 还有一个事,每个run job都会调用results job的。但是我们只希望最后一个run job结束后才让results job调用下游的report job 来生成report并发送邮件。所以我们的shell脚本中才会有判断当前还有没有run job运行的逻辑。没有了才会调用report job
report job终于到了report job。我们做了一堆配置,写了一堆脚本就是为了能成功合并测试结果并生成html的report。这个job的任务非常简单,results job已经把之前运行的所有测试的结果copy到了report job的workspace下。所以它要做的事情只有两件事,合并测试结果生成report以及发送邮件。 由于我用的report框架是allure,所以直接用的jenkins上针对这个框架的插件。所以配置基本是很简单的。如下:

https://testerhome.com/uploads/photo/2016/cb9cf1a844d7638e5322575dc5cf97f0.png%21large


每一种report框架都会有merge 测试结果的机制。大家根据自己的使用情况选择吧。
澄清我澄清一下我使用的框架吧。 语言是java,框架主要用的testng,selenide,maven。 report框架为allure。所以才有上面一整套的配置。如果大家用的技术体系不一样,上面的分发任务和生成report的配置可能是不一样的。
关于report框架:allure这个所谓的分布式执行处理的最大的难点其实就是测试结果的归集和html report的生成。我们起码有一半的工作都是为了达到这个目的。所以选取一个好的report框架是比较重要的。因为我是java系么。所以选择了allure。allure在merge测试结果方面挺方便的,同时我觉得allure是流程测试中尤其是UI自动化测试中最好的report框架。所以在这里还是小推销一下。它的效果图如下:

https://testerhome.com/uploads/photo/2016/adc38ac712934a20daeeccc71779dc94.png%21large



https://testerhome.com/uploads/photo/2016/00d210a349797f5f84f1de10859a7e9b.png%21large


可以看到它不仅有强大的测试分类功能。还可以详细的记录你每一步的操作并展示在report中。显示截图的功能也很棒。另外还有不同维度统计功能。例如这个时间统计:

https://testerhome.com/uploads/photo/2016/bf5e52eede68cf5648a42f25fc8e010f.png%21large


可以看到它展示了每台slave测试机上的case运行时间。可以让你调整用例的分组策略。不会让某一个group运行时间过长影响整体运行效率。下面是只列出失败的case:
https://testerhome.com/uploads/photo/2016/c517be7c9a7793f721d1f25a88f7c726.png%21large


下面是统计仪表盘:
https://testerhome.com/uploads/photo/2016/bc2d4c8ec13cb9fe829c4cae1e19b24f.png%21large


具体的使用攻略大家翻一翻我之前的帖子吧。我有一些详细说明。 也可以到git hub上直接看官方的wiki。

八戒你干嘛 发表于 2017-6-22 15:05:28

我现在做的是多进程启动多个appium执行,用分布式来弄,优点在哪里?一直不懂这块……

悠悠小仙仙 发表于 2017-6-22 15:06:15

八戒你干嘛 发表于 2017-6-22 15:05
我现在做的是多进程启动多个appium执行,用分布式来弄,优点在哪里?一直不懂这块……

我主要的目的就是增加执行速度么。分布式中的每台机器运行的case都是不一样的。我做PC端的web UI自动化没办法在一台机器上起多个浏览器进行测试。以前尝试过多个浏览器并发运行会出问题。你的多进程启动多个appium,也是在不同的手机上吧?
页: [1]
查看完整版本: 测试开发之路--分布式用例执行