开源测试工具 【开源】自动化巡检系统,基于 Testng + Playwright + SpringBoot + Vue + Ant-Design

DeX · 2024年10月31日 · 最后由 DeX 回复于 2024年11月07日 · 11852 次阅读

为方便 “及时” 感知 H5 页面服务是否存在稳定性问题,所以搭建一个基础巡检系统,用于检测 H5 页面是否正常,主动性感知页面异常从而快速处理问题,减少对线上服务的影响范围和时长。

基于Testng + Playwright + SpringBoot + Vue + Ant-Design,代码已开源在:https://github.com/TheCoolQATeam/online-inspection-tracker

出发点:遇到的问题、巡检必要性

  • 页面白页
  • 页面样式飞掉
  • 页面无响应

遇到上述问题,有众多原因:

  • 人为操作不当:配置文件错误、代码错误等
  • 依赖服务异常
  • 机房线路问题:阿里云崩了、腾讯云崩了等
  • 机器原因:降配、磁盘不足等导致
  • Nginx 负载问题
  • waf 误封禁
  • 域名被运营商封禁
  • cdn 原因
  • 。。。

如图,今年的热搜:
崩了

  • 内部的 119 反馈群中,某某城市页面打不开、崩了之类的反馈
  • boss:技术团队在干什么,这么严重的问题都没发现

遇到上述情形,我想没有任何一个 QA 会轻松吧,都是泪

故,基于这些痛点,搭建一套自动化巡检系统的必要性不用多说吧


实现方案

整体使用Testng + Playwright + SpringBoot + Vue + Ant-Design搭建自动化巡检系统,有以下优势:

  • 轻量:基于 SpringBoot 和 VUE,使用前后端开发模式,便于把测试用例、数据报告等进行落库和前端展示,非常轻量,易于搭建
  • 快速:基于 Playwright,使用 Playwright 请求页面、截取页面元素、页面截图、性能分析、网络请求资源分析等,非常高效快速
  • 稳定:基于 Testng,使用 Testng 的断言、参数化、Listener 监听、失败重试、数据报告等功能,易于上手

代码已开源在:https://github.com/TheCoolQATeam/online-inspection-tracker

Demo 试用,一看便知

减少贴子内容篇幅,如何使用就不详细说了,一看便知

demo 地址:https://check.itest.ren/

两种报警信息,一种是主要元素断言失败的报警,一种是视觉回归/图片对比失败的报警

提醒线上巡检有报警
测试描述遍历页面可用状态
测试类和方法AutoCheckHtml.testHtmlServiceability(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)[pri:0, instance:com.onlines.onlineSaleTest.AutoCheckHtml@3d5a813c]
测试用例156;;线上自动化巡检系统https://check.itest.ren;
提醒线上巡检有报警测试描述
线上自动化巡检系统
图片像素对比异常url地址
https://check.itest.ren
图片异常地址
https://xxxxxx.com/faf28987e446835a576383a78a208911.png

主要巡检功能及核心源码

页面主要元素检测

请求页面后,对页面进行截图,检测页面的 title 是否正常,正常则代表页面 HTML 已进行渲染,否则代表页面 HTML 未渲染,页面无法正常访问。

@Test(description = "遍历页面可用状态", dataProvider = "HtmlData")
public void testHtmlServiceability(int id, String htmlinfo, String title, String url, String dingKey, String wechatKey, String feishuKey) throws FileNotFoundException, UnknownHostException {
    page.navigate(url);
    long currentTimeMillis = System.currentTimeMillis();
    // 获取当前工作目录
    String userDir = System.getProperty("user.dir");
    String titleCleanInvalid = StrUtil.replace(StrUtil.replace(FileNameUtil.cleanInvalid(title), " ", "_"), "\t", "");
    String imageName = titleCleanInvalid.concat("_").concat(Long.toString(currentTimeMillis));
    logger.info("基准值地址"+imageName);
    // 使用String的concat()方法拼接路径
    String imagePath = userDir.concat(File.separator).concat("online-images").concat(File.separator).concat(imageName).concat(".png");
    page.waitForLoadState(LoadState.NETWORKIDLE); // 资源下载完毕
    page.screenshot(new Page.ScreenshotOptions().setPath(Paths.get(imagePath)));
    Assert.assertEquals(page.title(), title);
}

测试用例利用 TestNg 参数化功能从数据库中进行获取和转化为参数化类型,实现数据驱动;使用 mybatis 从数据库取数据

@DataProvider
public Object[][] HtmlData() {
    List<OnlinesPatrol> onlinesPatrols = onlinesPatrolMapper.selectDate();
    if (onlinesPatrols == null) {
        return null;
    }
    Object[][] pageData = new Object[onlinesPatrols.size()][7];
    for (int i = 0; i < onlinesPatrols.size(); i++) {
        OnlinesPatrol onlinesPatrol = onlinesPatrols.get(i);
        pageData[i][0] = onlinesPatrol.getId();
        pageData[i][1] = onlinesPatrol.getHtmlinfo();
        pageData[i][2] = onlinesPatrol.getTitle();
        pageData[i][3] = onlinesPatrol.getUrl();
        pageData[i][4] = onlinesPatrol.getDingKey();
        pageData[i][5] = onlinesPatrol.getWechatKey();
        pageData[i][6] = onlinesPatrol.getFeishuKey();
    }
    return pageData;
}

视觉回归

首先,把第一次请求的页面截图作为基准值,

然后,后续的每次请求的页面截图与基准值进行对比,如果存在差异,则代表页面有异常,异常则会发送钉钉、企微、飞书等报警,需要及时处理。

图片对比的阈值设置为 60%,即如果两张图片的相似度低于 60%,则认为两张图片有差异,代表页面有异常。
实际使用中,经过大量测试,可以确定该阈值可以满足需求。

OnlinesPatrol onlinesPatrol = onlinesPatrolMapper.selectByPrimaryKey(id);
if (onlinesPatrol != null) { // 若无基准值
    if (onlinesPatrol.getDatumAddress() == null) {
        onlinesPatrol.setDatumAddress(imageName);
        onlinesPatrol.setDatumCreatetime(new Date());
        onlinesPatrolMapper.updateByPrimaryKey(onlinesPatrol);
    } else {
        String pic1 = imagePath;  // 本次图片
        logger.info("图片1的地址"+pic1);
        // 基准值图片
        String pic2 = userDir.concat(File.separator).concat("online-images").concat(File.separator).concat(onlinesPatrol.getDatumAddress()).concat(".png");//线上运行获取图片地址
        logger.info("图片2的地址"+pic2);
        String result = null;
        try {
            result = imageComp.compareImage(pic2, pic1);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        int xiangsi = Integer.parseInt(result);
        if (xiangsi > 60) {
            Assert.assertTrue(true);
            logger.info("图片对比相似率大于60:" + xiangsi);
        } else {
            String ip = InetAddress.getLocalHost().getHostAddress();
            logger.info("服务器IP地址:" + ip);
            String picUrl = "http://" + ip + ":9091/patrol/onlines/images?imageName=" + imageName;
            DingUtil.sendMsgPic(url, id, picUrl, title, dingKey);
            WechatUtil.sendMsgPic(url, id, picUrl, title, wechatKey);
            FeishuUtil.sendMsgPic(url, id, picUrl, title, feishuKey);
            logger.info("图片对比相似率小于60:" + xiangsi);
        }
    }

性能分析

性能分析有两块,一块是计算测试用例的执行时间,另一块是通过 playwright 执行 js 脚本window.performance.timing计算页面加载时间

// 获取性能数据
Object performanceResult = page.evaluate("() => {\n" +
        "const timing = window.performance.timing; \n" +
        "return  JSON.stringify(timing.toJSON()); \n" +
        "}");

网络请求资源分析

playwright 的onRequest方法可以监听到所有的请求,通过判断请求的 url 等信息是否是正常请求,如果不是正常请求,则发送报警。

noLoginPage.onRequest((request) -> {
    try {
        getTestUrl(idForEnv, request.url());
    } catch (Exception e) {
        e.printStackTrace();
    }
});

定时巡检

定时功能有很多方案,本次开源项目使用ScheduledExecutorService,较为轻量

设置定时执行间隔为 5 分钟进行巡检一次,每天会巡检 288 次。

开源

项目开源地址:https://github.com/TheCoolQATeam/online-inspection-tracker

最后,欢迎一起迭代维护,记得 star~

共收到 20 条回复 时间 点赞

视觉回归有点意思

有点意思,先点个赞再说

先赞后看😋

话说用例在哪写,没太看明白

看到了,写用例的话有先从那个文件开始,以及怎么串联,大佬有时间可以补充下

DeX #6 · 2024年11月01日 Author
King 回复

开发了前端页面供添加用例,其实就是加上 URL、页面标题、报警机器人等信息,图片对比是默认进行的

不好意思,贴子篇幅较少,只写了主要的原理,没写前端的东西;
我搭建了 demo 试用:https://check.itest.ren/

好东西!比那些个搞 AI 噱头的玩意强太多

明白了,只需要在前台输入要巡检的 URL 就可以实现 UI 自动化巡检,程序自动跑

同个页面如果有弹窗或者多个 tab 页,能巡检到吗

22 年的时候也有想过做视觉回归相关,不过项目对图片精度的要求太高了,阈值也不好设置,就没下文了

DeX #11 · 2024年11月01日 Author
mumugc 回复

确认下问题,是检测是否正常弹窗、是否正常加载多个 tab 页吗?
如果是,目前代码版本不支持,需要开发下,二开也很容易的。

当前版本,主要是校验 H5 页面的 title 和截图进行对比相似度是否达到 60%,有异常进行报警

DeX #12 · 2024年11月01日 Author
King 回复

yes

没记错的话,关于视觉对比的,美团也有类似开源的项目:https://github.com/Meituan-Dianping/vision-ui

DeX #14 · 2024年11月02日 Author
鲨鱼辣椒 回复

目前实现的也是有点粗暴的,纯靠 cpu 像素对比的

DeX #15 · 2024年11月04日 Author
干饭狂人 回复

美团的这个高级多了

认证怎么处理的啊

DeX #17 · 2024年11月05日 Author
王十三 回复

playwright 支持 Context 上下文处理,可以 new 两个 context 对象,一个是未登录认证的,一个是认证编码的
示例:

@BeforeClass
    public void beforeClass() throws Exception {
        browser = playwright.chromium().launch(new BrowserType.LaunchOptions().setHeadless(true));
        noLoginContext = browser.newContext();
        loginContext = browser.newContext();
        loginPage = loginContext.newPage();
        loginPage.context().addCookies(_cookies);  // 添加cookie,或者不用手动添加cookie的方法,自行请求登录页面输入账号密码也是可以的
  }
此后使用loginContext 进行newPage()和navigate()即是登录态进行处理请求了


playwright的context是非常好用的就像写测试代码一样处理不知道是否达成你的需求

demo 怎么打不开呢

恒温 回复

视觉回归,https://github.com/amazingTest/Pic-Diff-Recognizer 好久前搞过,按一定深度去遍历所有页面做为基准,然后后续按照基准去判断相似度,并圈出不一致的地方

DeX #20 · 2024年11月07日 Author
LLLtt 回复

还真不好调整,试试重新刷新,或者自行搭建一个试试,Java+vue 栈搭建很容易的,
demo 是用大善人 CF + 个人家宽移动网 + 迷你主机搭建的,可能有网络问题

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册