前端自动化之性能测试

71 阅读5分钟

前言

前端自动化测试是前端同学在开发过程中必不可少的技能,拥有了这项技能,我们可以及时发现问题解决问题,让代码更健壮,让功能更可靠,让性能更优化!

搭建一个简单的测试项目

执行命令 npm init -y

image.png

然后打开编译器(我用vsCode)的终端,安装依赖 npm install,一个简单的项目就搭建成功了!

image.png

这里我们借助于Puppeteer, 它是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。 Puppeteer API 是分层次的,反映了浏览器结构。www.w3cschool.cn/puppeteer/p…

执行命令 npm install puppeteer-core

puppeteer-core的体积相对puppeteer小很多,因为它不包含浏览器内核,我们每个人的电脑上都有浏览器,只要指定浏览器的安装地址即可使用。

实现一个首屏渲染时间测试功能

在我们创建好的项目根目录下,新建一个index.js文件,直接上代码

const pup = require("puppeteer-core");
async function run() {
  //注册浏览器
  //由于puppeteer-core不包含浏览器内核,需要给出电脑浏览器的安装地址
  const browser = await pup.launch({
    executablePath: "C:/Program Files/Google/Chrome/Application/chrome.exe", //浏览器安装地址
  });
  //打开页面
  const page = await browser.newPage();
  //开始时间
  const startTime = performance.now();
  await page.goto("https://sports.qq.com/");
  //结束时间
  const endTime = performance.now();
  //计算时间差(秒)
  const time = endTime - startTime;
  console.log("页面打开时间:", time);
  //关闭浏览器
  //await browser.close();
}
run();

我们随便测试一个网页的打开时间,然后在终端执行命令 node index.js

image.png

获取performance.timing

performance有一个timing属性,里面记录了很多指标,我们可以查看一下

const pup = require("puppeteer-core");
async function run() {
  //注册浏览器
  //由于puppeteer-core不包含浏览器内核,需要给出电脑浏览器的安装地址
  const browser = await pup.launch({
    executablePath: "C:/Program Files/Google/Chrome/Application/chrome.exe", //浏览器安装地址
    headless: false, //是否无头浏览器
  });
  //打开页面
  const page = await browser.newPage();
  //开始时间
  const startTime = performance.now();
  await page.goto("https://www.baidu.com/");
  //结束时间
  const endTime = performance.now();
  //计算时间差(秒)
  const time = endTime - startTime;
  console.log("页面打开时间:", time);

  //打开浏览器环境 获取performance.timing
  let timing = JSON.parse(
    await page.evaluate(() => {
      //获取performance.timing
      return JSON.stringify(window.performance.timing);
    })
  );
  console.log("timing:", timing);

  //关闭浏览器
  //await browser.close();
}
run();

再到控制台运行 node index.js

image.png

就可以看到timing对象的各种属性值。

计算页面某个核心区域出现的时间

背景:页面区域的内容需要异步请求从后端获取来渲染,我们需要知道这部门的内容用户需要等待多久才可以看到。

我准备了一个例子,看代码:

import { useEffect, useState } from "react";
import "./inde.css";

const Login = () => {
  //定义一个数组类型
  type ArrayObj = Array<number>;

  const [dataList, setDataList] = useState([] as ArrayObj);
  useEffect(() => {
    setTimeout(() => {
      setDataList([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    }, 2000);
  }, []);

  return (
    <div className="login-container">
      {/* <div className="point"></div> */}
      {dataList.map((item, index) => {
        return (
          <div className="list-item" key={index}>
            {item}
          </div>
        );
      })}
    </div>
  );
};

export default Login;


这是一个用react写的页面,里面模拟了异步请求,渲染数据列表,页面是这样的:

image.png

我们接下来就要测试这个列表开始获取,到浏览器渲染完成需要多久!!!

我们重新在测试项目中创建一个index2.js,代码如下:

const pup = require("puppeteer-core");
async function run() {
  //注册浏览器
  //由于puppeteer-core不包含浏览器内核,需要给出电脑浏览器的安装地址
  const browser = await pup.launch({
    executablePath: "C:/Program Files/Google/Chrome/Application/chrome.exe", //浏览器安装地址
    headless: false, //是否无头浏览器
  });
  //打开页面
  const page = await browser.newPage();
  //开始时间
  const startTime = performance.now();
  await page.goto("http://localhost:5173/#/login");
  //等到list-item这个元素可以被选择,即等到list-item这个元素被渲染出来
  await page.waitForSelector(".list-item");

  //结束时间
  const endTime = performance.now();
  //计算时间差(秒)
  const time = endTime - startTime;
  console.log("list渲染完成时间:", timing);

  //关闭浏览器
  //await browser.close();
}
run();

这里我们用了一个 page.waitForSelector(".list-item") 函数,意思就是等到list-item这个元素可以被选择,即等到list-item这个元素被渲染出来,然后我们再计算时间差,执行代码:

image.png

计算某个链路的完成时间(不考虑人类反应速度,纯粹程序本身完成某个操作链路需要的时间)

我创建了一个登录环境,登录成功后跳转到上面包含列表的页面,上代码:

const pup = require("puppeteer-core");
async function run() {
  //注册浏览器
  //由于puppeteer-core不包含浏览器内核,需要给出电脑浏览器的安装地址
  const browser = await pup.launch({
    executablePath: "C:/Program Files/Google/Chrome/Application/chrome.exe", //浏览器安装地址
    headless: false, //是否无头浏览器
  });
  //打开页面
  const page = await browser.newPage();
  //开始时间
  const startTime = performance.now();
  await page.goto("http://localhost:5173/#/login");
  const user = await page.$(".username"); //获取用户名
  const password = await page.$(".password"); //获取密码
  await user.type("admin"); //输入用户名
  await password.type("admin"); //输入密码
  const button = await page.$(".login-btn"); //获取登录按钮
  await button.click(); //点击登录按钮
  await page.waitForNavigation(); //等待页面跳转
  //等到list-item这个元素可以被选择,即等到list-item这个元素被渲染出来
  await page.waitForSelector(".list-item");

  //结束时间
  const endTime = performance.now();
  //计算时间差(秒)
  const time = endTime - startTime;
  console.log("list渲染完成时间:", time);

  //关闭浏览器
  //await browser.close();
}
run();

从登录到list-item渲染完成,这个过程被称为一个功能链路,这个过程的完整消耗时间我们就可以计算出来了,如图:

image.png

这种测试其实人工来完成是比较难的,我们还可以进行多次循环,比如调用run()方法100次,来看一个平均值等。

通过脚本link为全局指令

我们每次测试都更改源码显然是不合适的,我们需要把每一个测试独立出来,放到配置文件中,通过命令的形式指定执行某一个文件。

//package.json文件增加bin属性
{
  "name": "autoTest",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "bin": {
    "stest": "./index3.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "puppeteer-core": "^23.4.1"
  }
}

最终我们只要在控制台输入stest,就可以自动执行index3.js这个测试任务,但在这之前,需要给index3.js指定环境,如图:

#! /usr/bin/env node
//指定使用node环境

const pup = require("puppeteer-core");
async function run() {
  //注册浏览器
  //由于puppeteer-core不包含浏览器内核,需要给出电脑浏览器的安装地址
  const browser = await pup.launch({
    executablePath: "C:/Program Files/Google/Chrome/Application/chrome.exe", //浏览器安装地址
    headless: false, //是否无头浏览器
  });
  //打开页面
  const page = await browser.newPage();
  //开始时间
  const startTime = performance.now();
  await page.goto("http://localhost:5173/#/login");
  const user = await page.$(".username"); //获取用户名
  const password = await page.$(".password"); //获取密码
  await user.type("admin"); //输入用户名
  await password.type("admin"); //输入密码
  const button = await page.$(".login-btn"); //获取登录按钮
  await button.click(); //点击登录按钮
  await page.waitForNavigation(); //等待页面跳转
  //等到list-item这个元素可以被选择,即等到list-item这个元素被渲染出来
  await page.waitForSelector(".list-item");

  //结束时间
  const endTime = performance.now();
  //计算时间差(秒)
  const time = endTime - startTime;
  console.log("list渲染完成时间:", time);

  //关闭浏览器
  //await browser.close();
}
run();

如上图,在index3.js顶部添加 #! /usr/bin/env node,来查找node环境进行运行。

然后我们打开控制台 输入指令 npm link (npm link用来在本地项目和本地npm包之间建立连接,可以在本地进行模块测试),然后输入 stest ,就可以自动执行index3.js文件中的测试功能了,效果如图:

image.png

我们也可以将地址进行动态处理,如图:

image.png

这样我们在输入stest 后面就可以跟一个地址参数,比如 stest http://localhost:5173/#/login 这样就可以动态测试任何地址了,如图:

image.png