目前我们在持续开发着一个几十个页面,十万+行代码的项目,随着产品的更迭,总会出现这样的问题。在对某些业务逻辑或者功能进行添加或者修改的时候(尤其是通用逻辑),这些通用的逻辑或者组件往往会牵扯到一些其他地方的问题。由于测试人员受限,我们很难在完成一个模块单元后,对所有功能重新测试一遍。
同时,由于环境及数据的区别,(以及在开发过程中对代码完备性的疏忽),代码会在某些特殊数据的解析和和展示上出现问题,在开发和测试中很难去发现。总的来说,我们希望有一个这样的工具,帮我们解决上述几个问题:
在进行代码和功能改动后,能够自动访问各个功能的页面,检测问题
针对大量的数据内容,进行批量访问,检测对于不同数据的展示是否存在问题
测试与代码功能尽量不耦合,避免每次上新功能都需要对测试用例进行修改,维护成本太大
定期的测试任务,及时发现数据平台针对新数据的展示完备性
其中,最重要的问题,就是将测试代码与功能解耦,避免每次迭代和修改都需要追加新的测试用例。我们如何做到这一点呢?首先我们来梳理下测试平台的功能。
功能设定
由于我们的平台主要是进行数据展示,所以我们在测试过程中,主要以日常的展示数据为重心即可,针对一些复杂的表单操作先不予处理。针对上述的几个问题,我们针对自动化测试工具的功能如下:
依次访问各个页面
访问各个页面的具体内容,如时间切换、选项卡切换、分页切换、表格展开行等等
针对数据表格中的详情链接,选择前100条进行访问,并进行下钻页的继续测试
捕获在页面中的错误请求
对错误信息进行捕获,统计和上报
根据以上的梳理,我们可以把整个应用分为几个测试单元
页面单元,检测各功能页面访问的稳定性
详情页单元,根据页面的数据列表,进行批量的详情页跳转,检测不同参数下详情页的稳定性
功能单元,用于检测页面和详情页各种展示类型点击切换后是否产生错误
通过这样的划分,我们针对各个单元进行具体的测试逻辑书写用例,这样就可以避免再添加新功能和页面时,频繁对测试用例进行修改了。
Puppeteer
带着上面我们的需求,我们来看下Puppeteer的功能和特性,是否能够满足我们的要求。
Puppeteer是一个Node库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。Puppeteer 默认以 headless 模式运行,但是可以通过修改配置文件运行“有头”模式。
我们可以使用Puppeteer完成以下工作:
访问页面,进行截图
自动进行键盘输入,提交表单
模拟点击等用户操作
等等等等。。
我们来通过一些小案例,来介绍他们的基本功能:
访问一个带有ba认证的网站
puppeteer可以创建page实例,并使用goto方法进行页面访问,page包含一系列方法,可以对页面进行各种操作。
(async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); // ba认证 await page.authenticate({ username, password }); // 访问页面 await page.goto('https://example.com'); // 进行截图 await page.screenshot({path: 'example.png'}); await browser.close(); })();
访问登陆页面,并进行登录
首先,对于SPA(单页面应用),我们都知道,当页面进入后,客户端代码才开始进行渲染工作。我们需要等到页面内容渲染完成后,再进行对应的操作。我们有以下几种方法来使用
waitUntil
puppeteer针对页面的访问,切换等,提供了waitUntil参数,来确定满足什么条件才认为页面跳转完成。包括以下事件:
load - 页面的load事件触发时
domcontentloaded - 页面的DOMContentLoaded事件触发时
networkidle0 - 不再有网络连接时触发(至少500毫秒后)
networkidle2 - 只有2个网络连接时触发(至少500毫秒后)
通过waitUnitl,我们可以当页面请求都完成之后,确定页面已经访问完成。
waitFor
waitFor方法可以在指定动作完成后才进行resolve
// wait for selector await page.waitFor('.foo'); // wait for 1 second await page.waitFor(1000); // wait for predicate await page.waitFor(() => !!document.querySelector('.foo'));
我们可以利用waitForSelector方法,当登录框渲染成功后,才进行登录操作