Chrome remote debugging protocol在自动化测试中的应用和实践

简介: 从selenium说起虽然我们的主题是cdp(chrome debug protocol)的应用,但在介绍cdp之前,不得不先从selenium说起,因为这两者有密不可分的关系。

从selenium说起

虽然我们的主题是cdp(chrome debug protocol)的应用,但在介绍cdp之前,不得不先从selenium说起,因为这两者有密不可分的关系。

我们知道,在最新的selenium里,当你去执行一个测试动作,例如打开浏览器,然后输入网址,找到一个搜索框填入文本并点击搜索,这背后所依赖的技术,其实是webdriver,而当你的动作执行在chrome浏览器上,更为细化的说,依赖的是chromewebdriver。

我们详细的来分析这一流程,你会更清楚的知道cdp与此有何关系。

首先我们来写一个示例代码:

from selenium import webdriver

driver = webdriver.Chrome()
driver.get("https://www.baidu.com/")

执行这段代码,会看到系统启动了chrome浏览器,并跳转到了百度首页。

看driver = webdriver.Chrome()这一句,以下是这段代码的流程图解。

img_a447cdc9c0062096df418433b70dd94b.png
初始化chrome()的流程图解.png

可以看到在这个流程中,chromedriver起到的是桥梁的作用,他接受客户端的请求,然后转化为浏览器的标准指令操作浏览器,而在后半部分,也就是指令如何让浏览器工作中,就涉及到了我们的主题cdp,因为这部分的标准其实就是cdp。

什么是cdp

chrome debug protocol,简称cdp。

大家应该都用过chrome浏览器的F12,也就是devtools,其实这是一个web应用,当你使用devtools的时候,浏览器本身会作为一个服务端,而你看到的浏览器调试工具界面,其实只是一个前端应用,在这中间通信的,就是cdp,他是基于websocket的,一个让devtools和浏览器内核交换数据的通道。

cdp本身是可开放的,换句话说,你用devtools能做什么(例如操作浏览器,获取网络信息,获取js覆盖数据,获取性能数据等等),你就能用cdp做什么。

cdp的官方文档地址,可以点击查阅,这里再简单的介绍一下。

cdp把不同的操作划分为了不同的域(domain),每个域负责不同的功能模块,例如,Page域可以获取当前页面数据,或者操作页面跳转等等;Profiler域可以获取当前的页面的js覆盖率数据等等;

直接引用FEX的一篇文章来解释:

该协议把操作划分为不同的域(domain),比如 DOM、Debugger、Network、Console 和 Timeline 等,可以理解为 DevTools 中的不同功能模块。

每个域(domain)定义了它所支持的 command 和它所产生的 event。

每个 command 包含 request 和 response 两部分,request 部分指定所要进行的操作以及操作说要的参数,response 部分表明操作状态,成功或失败。

command 和 event 中可能涉及到非基本数据类型,在 domain 中被归为 Type,比如:’frameId’: <FrameId>,其中 FrameId 为非基本数据类型

至此,不难理解:

domain = command + event + type

使用cdp的方式

最原始的使用cdp的方式可以参照google的cdp文档来:

1.使用附加参数打开chrome的远程调试协议开关(普通模式下的chrome浏览器是无法直接使用cdp通信的,另外,请注意,在不同的操作系统下指令细节会有所不同),

chrome.exe --remote-debugging-port = 9222

此时一个打开的远程调试协议的浏览器实例被启动。

2.为做演示,在打开的浏览器中,输入百度的网址并进入,新开一个tab,进入网址http://localhost:9222,此时应该如截图所示:

img_d49e7b63cdc22961fb74ea91f374654e.png
点击标签.png

3.点击百度这个标签,进入他的devtools界面,看一下地址栏,记录page/后面的通信标识值,然后在console里输入以下代码:

var ws = new WebSocket('ws://localhost:9222/devtools/page/这里填刚才记录的标识值');    

ws.send('{"id": 1, "method": "Page.navigate", "params": {"url": "http://www.soso.com"}}')

执行完会发现,刚才的百度页面,跳转到了soso的页面,其实这段代码就是新开了一个websocket连接到刚才的百度页面的调试地址,然后通过page域的navigate方法让该页面重新跳转到了指定地址。

需要注意的一点是,在这里,每个tab(页面)都只有一个单独的通信地址,且每个地址只能与对应的tab通信。

以上就是比较原始的使用方法,实际上,cdp有很多封装好的库可以使用,例如python的PyChromeDevTools库,nodejs的chrome-remote-interface库等等,更多上层封装库请参见官方文档

cdp在自动化中的应用和实践

看了以上内容,可能你会得出一个结论,selenium依赖webdriver,而在chrome浏览器中,webdriver又依赖chromedriver,chromedriver又是依赖cdp的;那么,我使用selenium和我直接使用cdp,有什么区别呢?

实际上真要较真(不怕麻烦)的话,是没有区别的,但二者还是有一些差异的,selenium的封装更为上层,使得你不用去关心原始的cdp到底如何使用,而且也集成了聚焦测试所需要的一些功能,例如分布式执行,docker image等等,使得在测试这个需求上,更为方便;而直接使用cdp的话,会让整个结构更为简洁,而且,有些操作由于webdriver没有封装(例如获取性能数据,获取js覆盖率等等),所以直接使用cdp会更为精准。那么有没有办法让二者的优点结合呢?

在这里我发现了两种方案可以做到,

1.通过命令行启动开启了调试协议的chrome浏览器,然后在selenium里,初始化webdriver时指定ChromeOption的__debugger_address的值为之前的远程调试地址,然后使用selenium操作webdriver,使用PyChromeDevTools操作cdp,示例代码如下:

import os
import PyChromeDevTools
from selenium import webdriver

cmd = "chrome.exe --remote-debugging-port=9222"
os.popen(cmd) #此时chrome浏览器打开
time.sleep(3)
chrome = PyChromeDevTools.ChromeInterface()#使用chrome操作cdp
options = webdriver.ChromeOptions()
options._debugger_address = "localhost:9222"
driver = webdriver.Chrome(chrome_options=self.options)

2.可以直接使用selenium的预留cdp通信方法execute_cdp_cmd,示例代码如下:

from selenium import webdriver

driver = webdriver.Chrome()
driver.get("https://www.baidu.com/")
driver.execute_cdp_cmd('Page.navigate',{"url": "http://www.soso.com"})

利用cdp获取页面网络数据

有时候当脚本出错了,我们会希望获得更多的信息去排查,如果这时候能重现当时的网络请求,那么排查会容易的多,下面是一个获取页面网络数据(response值)的例子,这里只拿了请求的response值,但实际上稍加改动就可以把请求信息拿全(request+response),为了方便演示上面两种方法,这里混用了上面的两个方案。

from selenium import webdriver
import time
import os
import PyChromeDevTools

os.chdir(r"C:\Users\zyj\AppData\Local\Google\Chrome SxS\Application") #这里是改变了当前环境变量
cmd = "chrome.exe --remote-debugging-port=9222"
os.popen(cmd)#启动chrome浏览器
time.sleep(3)
chrome = PyChromeDevTools.ChromeInterface()
options = webdriver.ChromeOptions()
options._debugger_address = "localhost:9222"
driver = webdriver.Chrome(chrome_options=options)
chrome.Network.enable()#开启页面的网络信息收集模式
time.sleep(2)
driver.execute_cdp_cmd('Page.navigate',{"url": "http://www.mycaigou.com"})#跳转到mycaigou,这里用的selenium的execute_cdp_cmd方法做到的
responseReceived = chrome.wait_event("Network.responseReceived", timeout=60)#等待response收集事件结束,获取收集信息,这里的信息不包含详细的response内容,需要用到方法getResponseBody
resquest_id = responseReceived[0]['params']['requestId']#这个id是指你想要收集哪个请求的信息,他是请求的唯一标示,这里随便拿了一个,没做遍历
res = chrome.Network.getResponseBody(requestId=resquest_id)#传入id,拿到请求的返回值
print(res)

利用cdp获取页面加载时间

这是PyChromeDevTools的官方例子,演示如何获取页面加载时间:

import PyChromeDevTools
import time
import os

os.chdir(r"C:\Users\zyj\AppData\Local\Google\Chrome SxS\Application") #这里是改变了当前环境变量
cmd = "chrome.exe --remote-debugging-port=9222"
os.popen(cmd)#启动chrome浏览器
chrome = PyChromeDevTools.ChromeInterface()
chrome.Network.enable()
chrome.Page.enable()
start_time=time.time()
chrome.Page.navigate(url="http://www.baidu.com/")
chrome.wait_event("Page.loadEventFired", timeout=60)#loadEventFired是页面全部加载完毕的时间,实际上这里还可以用reload方法,选择去除缓存加载,这样的时间会更加精确
end_time=time.time()

print ("Page Loading Time:", end_time-start_time)

利用cdp拿到自动化测试后的js覆盖率数据并展示

在cdp中,是无法直接得到覆盖率的数据的,有关js代码执行情况的统计,在Profiler域,我们可以使用takePreciseCoverage方法来拿到js执行数据,这个数据的数据结构是这样的:

    'result': {
        'result': [{
            'scriptId': '17',
            'url':'https://www.xxxxxxxxx.com/browser/guide.js',
            'functions': [{
                'functionName': 'get',
                'ranges': [{
                    'startOffset': 0,
                    'endOffset': 4273,
                    'count': 1
                }],
                'isBlockCoverage': False
            },
            }],
        }],
    }
        ......

一个result包含多个js的统计情况,每个url基本就是js的请求地址;在每个js的统计情况里,又有多个function的统计情况,每个function里的startOffset和endOffset指的是这个方法的被统计语句按字节位置来算的开始位置和结束位置,count代表这段语句是否被执行到,1代表是,0代表否。

因此,思路就是,拿到测试完成后的js统计数据,然后通过每个js统计数据里的每个function的统计坐标值和统计状态,和原始js数据比对,从而实现对js覆盖状况的总览。

这个实现比较复杂,我直接做成了一个模块,只需要接受takePreciseCoverage的数据,就可以计算出覆盖情况并直观的展示,具体的代码在github上,这里就不放出了。

最终的效果图演示:

img_d175b822bbe4517076ddcce9d6c6a3f1.png
覆盖率效果展示.png

目录
相关文章
|
3天前
|
机器学习/深度学习 人工智能 算法
深入理解与实践:基于AI的软件测试自动化
【5月更文挑战第1天】随着人工智能的不断发展,其在软件测试中的应用也日益广泛。本文将探讨如何利用AI进行软件测试自动化,包括其理论基础、实现方式以及在实际中的应用。我们将通过实例分析,展示AI在提高软件测试效率和质量方面的巨大潜力。
|
3天前
|
敏捷开发 运维 测试技术
构建高效自动化运维体系:基于容器技术的持续集成与持续部署实践
【4月更文挑战第30天】在数字化转型的浪潮中,企业对软件交付速度和质量的要求日益提高。自动化运维作为提升效率、确保稳定性的关键手段,其重要性不言而喻。本文将探讨如何利用容器技术构建一个高效的自动化运维体系,实现从代码提交到产品上线的持续集成(CI)与持续部署(CD)。通过分析现代容器技术与传统虚拟化的差异,阐述容器化带来的轻量化、快速部署及易于管理的优势,并结合实例讲解如何在实际环境中搭建起一套完善的CI/CD流程。
|
3天前
|
敏捷开发 测试技术 持续交付
探索自动化测试在敏捷开发中的应用移动应用的未来:跨平台开发与操作系统的融合
【4月更文挑战第30天】随着软件开发周期的不断缩短,传统的软件测试方法逐渐显得力不从心。本文将深入探讨自动化测试在敏捷开发环境中的关键作用,分析其如何提高测试效率、减少人力资源成本,并确保软件产品的质量与稳定性。通过案例分析,我们还将讨论实施自动化测试的最佳实践和面临的挑战,为追求高效敏捷开发的组织提供参考。
|
4天前
|
数据采集 机器学习/深度学习 人工智能
自动化测试中AI辅助技术的应用与挑战
【4月更文挑战第30天】随着人工智能(AI)技术的飞速发展,其在软件自动化测试领域的应用日益增多。本文探讨了AI辅助技术在自动化测试中的应用情况,包括智能化测试用例生成、测试执行监控、缺陷预测及测试结果分析等方面。同时,文章还分析了在融合AI技术时所面临的挑战,如数据质量要求、模型的透明度与解释性问题以及技术整合成本等,并提出了相应的解决策略。
|
4天前
|
机器学习/深度学习 数据采集 算法
【Python机器学习专栏】自动化特征选择与优化的实践
【4月更文挑战第30天】特征选择在机器学习中至关重要,能降低模型复杂度,提高泛化能力和避免过拟合。本文介绍了自动化特征选择的三种方法:过滤法(如SelectKBest)、包装法(如RFE)和嵌入法(如随机森林)。通过结合这些方法,可实现特征优化,包括数据预处理、初步筛选、模型训练与评估、特征优化和结果验证。自动化特征选择能提升模型性能,适应不同数据集和任务需求,为机器学习项目提供坚实基础。
|
4天前
|
前端开发 IDE 数据可视化
深入理解与应用自动化测试框架Selenium的最佳实践
【4月更文挑战第30天】 本文将深入剖析自动化测试框架Selenium的核心原理,并结合最佳实践案例,探讨如何有效提升测试覆盖率和效率。文中不仅涉及Selenium的架构解析,还将提供针对性的策略来优化测试脚本,确保测试流程的稳定性与可靠性。通过实例演示,读者可以掌握如何在不同测试场景中灵活运用Selenium,以及如何处理常见的技术挑战。
|
4天前
|
中间件 测试技术 API
探索自动化测试工具的新边界:Selenium与Appium的集成实践
【4月更文挑战第30天】 随着移动应用和Web应用的不断融合,传统的自动化测试工具需要适应新的测试环境。本文将详细分析Selenium和Appium这两款流行的自动化测试工具的集成实践,探讨如何构建一个能够同时支持Web和移动端应用的自动化测试框架。通过对比两者的技术架构、功能特性以及在实际项目中的集成过程,我们旨在为读者提供一个清晰的指导,帮助他们在复杂的应用环境中实现高效、稳定的自动化测试流程。
|
4天前
|
运维 Kubernetes 持续交付
构建高效自动化运维系统:基于容器技术的持续集成与持续部署实践
【4月更文挑战第30天】 在快速发展的云计算时代,传统的运维模式已无法满足敏捷开发和快速迭代的需求。本文将介绍如何利用容器技术搭建一套高效自动化运维系统,实现软件的持续集成(CI)与持续部署(CD)。文章首先探讨了现代运维面临的挑战,接着详细阐述了容器技术的核心组件和工作原理,最后通过实际案例展示了如何整合这些组件来构建一个可靠、可扩展的自动化运维平台。
|
4天前
|
机器学习/深度学习 运维 监控
构建高效自动化运维体系:从理论到实践
【4月更文挑战第30天】 在信息技术日益发展的今天,自动化运维已经成为提高系统稳定性、优化资源配置和降低人力成本的关键。本文旨在探讨如何构建一个高效的自动化运维体系,涵盖从初步规划到具体实施的全过程。文章首先分析了自动化运维的必要性,接着提出一套完整的构建方案,并详细阐述了关键技术与工具的选择和应用。通过案例分析,验证了所提方案的有效性,并对自动化运维的未来趋势进行了展望。
|
4天前
|
敏捷开发 监控 前端开发
深入理解与应用自动化测试框架:以Selenium为例
【4月更文挑战第30天】 在软件开发的快速迭代周期中,质量保证(QA)团队面临持续的压力,需确保产品在每次发布时都达到预期的质量标准。为了应对这一挑战,自动化测试成为了关键工具,它不仅提高了测试效率,还确保了测试的一致性和可重复性。本文将探讨自动化测试框架Selenium的核心组件、工作原理及其在实际测试中的应用。通过分析Selenium的优势和面临的常见问题,我们将讨论如何有效地集成Selenium到现有的测试流程中,以及如何克服常见的技术障碍。我们的目标是为读者提供一个清晰的指南,帮助他们理解和利用自动化测试框架来优化他们的软件测试实践。