一文,教你搭建前端自动化测试环境

前言

最近在看前端自动化测试相关的东西,在搭建环境的时候发现还是有许多需要注意的地方,而且网上很少有将各种测试(单元测试,集成测试,端对端测试)的环境搭建都提及的文章,对像我这样的新手不太友好,于是便打算删繁就简,希望通过这一篇文章能让大家Vue项目中自动化测试环境的搭建有个初步的认识,并且能够实现简单的测试用例,主要内容有:

  • 单元测试环境搭建与案例实践(非浏览器环境)* 使用Jest测试工具函数* 使用Jest+Vue Test Utils测试Vue组件
  • 端对端测试环境搭建与案例实践(浏览器环境)* 使用Cypress测试页面

之所以没提及集成测试,是因为对前端而言,很难区分出单元测试和集成测试,普遍认为前端中的单元测试包括了集成测试,有关三种测试的区别,通过下面一张表希望能让大家对单元/集成/端对端测试有个初步的认识,感兴趣的可以继续了解一下测试金字塔奖杯模型

单元测试集成测试端对端测试
测试对象代码单元(函数,模块等)组织在一起的代码单元整个页面或应用
作用保证代码单元在给给定输入下得到预期结果保证多个模块组织在一起可以正常工作模拟用户在真实环境中的操作,确保一切正常
测试环境非浏览器环境非浏览器环境浏览器环境
代表工具Jest,Mocha,Karma等Jest, Testing Library等Cypress,Puppeteer, NightWatch等

本文所用的框架是vue2,测试工具有JestVue Test UtilsCypress,选择它们的原因很简单:

图片来自于The State of JS 2021: 测试工具

好吧,其实是因为:

  • Jest👉All in one, 开箱即用* Vue Test Utils👉官网推荐* Cypress👉All in one, 开箱即用* * *

在开始之前,我们需要有一个新的vue2项目,这个相信大家有“手”(脚手架的手)就行,直接vue create first_test。这里选择的是默认安装,也可以利用脚手架安装测试框架,但这不太现实,因为我们往往是对一个已有的项目进行测试,而不是在开发阶段就已经考虑到了测试🤣🤣🤣

接下来我们一起在一个已有项目(这里是vue2新项目)中引入JestCypress

单元测试环境搭建与案例实践

安装 Jest

运行npm install jest --save-dev ,也可以使用简化的命令npm i jest -D

"devDependencies": {
	..."jest": "^29.1.2",...
}, 

函数测试实践

在项目根目录下新建tests/unit文件夹,用于存放单元测试的执行文件;在src目录下新建utils文件夹,用于存放工具函数。

F:. 
│--src 
│ │--utils 
|sum.js
│--tests
| │--unit
| first_unit.spec.js 

编写第一个单元测试用例first_unit.spec.js,来测试一个简单的求和函数sum.js,代码如下

// front_test/src/utils/sum.js

function sum(a, b) {return a + b;
}

module.exports = sum; 
// front_test/tests/unit/first_unit.spec.js

const sum = require("../../src/utils/sum");

describe("first jest test", () => {it("test 1", () => {expect(sum(1, 2)).toBe(3);});it("test 2", () => {expect(sum(Infinity, Infinity)).toBe(Infinity);});
}); 

package.json中配置启动命令

 "scripts": {"test:unit": "jest"}, 

然后在命令行输入npm run test:unit first_unit.spec.js,出现绿色的PASS就说明测试通过了🍻🍻🍻

Jest 常用配置

  • 配置Babel来让Jest支持ES6语法* npm install --save-dev babel-jest @babel/core @babel/preset-env babel-core@^7.0.0-bridge.0* 在babel.config.js中作如下配置module.exports = {presets: ["@babel/preset-env"],}; * 在项目根目录下新建jest的配置文件jest.config.js,作如下配置module.exports = {transform: {"\\.[jt]sx?$": "babel-jest", },}; * 配置别名* 在jest.config.js中添加如下配置module.exports = {moduleNameMapper: {"^@/(.*)$": "<rootDir>/src/$1",},}; * 以上配置完成后,first_unit.test.js中的const sum = require("../../src/utils/sum");就可以写成import sum from "@/utils/sum.js"了其它的诸如支持typescript、生成覆盖率文件、使用webpack等的配置方法可以根据自己的需要参考官网

Vue Test Utils 的安装与配置

使用Jest可以进行DOM测试、异步代码测试和快照测试等,但正如Jest本身的定位——一个令人愉快的javascript测试框架。也就是.js文件,所以要想对.vue文件进行测试,还需要安装Vue官方提供的Vue Test Utils库,按官方的说法就是,它“是偏底层的组件测试库,可以提供对 Vue 特定 API 的访问

运行npm install --save-dev @vue/test-utils@1 vue-jest,由于是vue2的项目,所以这里指定了@vue/test-utils的版本为v1

然后在jest.config.js中作如下配置

module.exports = {moduleFileExtensions: ["js", "json", "vue"],transform: {".*\\.(vue)$": "vue-jest",},
}; 

组件测试实践

src/components下新建Parent.vueChild.vue

// front_test/src/components/Parent.vue

<template><div><span v-show="showSpan">Parent</span><child v-if="showChild"></child> // Child组件</div>
</template>

<script>
import Child from "./Child.vue";
export default {name: "Parent",components: {Child,},data() {return {showSpan: false,showChild: false,};},
};
</script> 
// src/components/Child.vue

<template><div>Child</div>
</template>

<script>
export default {name: "Child",
};
</script> 

👉我们要测的是,在Parent.vue中:

  • showSpantrue时,span标签可以显示
  • Child组件默认不会显示

编写的测试用例first_vue.spec.js如下

// front_test/tests/unit/first_vue.spec.js
import { mount } from "@vue/test-utils";
import Parent from "@/components/Parent.vue";
import Child from "@/components/Child.vue";

describe("Parent", () => {it("does render a span", () => {const wrapper = mount(Parent, { // 挂载被测的组件data() {return {showSpan: true,};},});expect(wrapper.find("span").isVisible()).toBe(true); //find()用于查找元素,isVisible()用于测试v-show元素是否可见});it("does not render a Child component", () => {const wrapper = mount(Parent);expect(wrapper.findComponent(Child).exists()).toBe(false); //findComponent()用于查找组件,exist()用于测试v-if元素是否存在});
}); 

运行npm run test:unit first_vue.spec.js,但是报了如下错误

 > [vue-test-utils]: window is undefined, vue-test-utils needs to be run in a browser environment.
 > You can run the tests in node using jsdom 

这是jest版本的问题,解决方法是降为v27,并在jest.config.js中配置测试环境:

module.exports = {testEnvironment: "jsdom",
}; 

之后再运行npm run test first_vue.spec.js就可以了🍻🍻🍻

端对端测试环境搭建与案例实践

安装Cypress

Cypress的安装与Jest一样,直接npm i cypress -D

"devDependencies": {..."cypress": "^10.9.0",...
}, 

安装Cypress后,有两种方式可以打开Cypress

  • 直接在当前目录运行npx cypress open
  • 切到node_modules/.bin目录下运行cypress open

运行npx cypress open,会出现Cypress的UI界面,同时在项目根目录下会自动生成cypress文件夹和cypress.config.js配置文件,可以看到默认的测试用例first_e2e.cy.js通过

F:. 
│--cypress
| │--e2e // 存放测试用例
| | first_e2e.cy.js
| │--fixtures // 存放静态资源
| | example.json
| │--support // 配置全局注入文件
| command.js
| e2e.js
│--src 
// first_e2e.cy.js
describe("empty spec", () => {it("passes", () => {cy.visit("https://example.cypress.io");});
}); 

Cypress常用配置

  • 启动命令

package.json中配置启动命令

 "scripts": {"test:e2e": "cypress open"}, 

之后就可以使用npm run test:e2e来打开Cypress了

  • 项目文件夹

默认建立的cypress文件夹是在根目录下,为了方便管理,在之前建立的tests文件夹下新建e2e文件夹,并将cypress文件夹中的内容全部CV过去,同时在cypress.config.js文件中添加如下配置:

// cypress.config.js
baseUrl: "http://localhost:8080", // 默认测试域名
fixturesFolder: "tests/e2e/fixtures", // 外部静态数据
screenshotsFolder: "tests/e2e/screenshots", // 屏幕快照
videosFolder: "tests/e2e/videos", // 录制视频
specPattern: "tests/e2e/specs/*.cy.{js,jsx,ts,tsx}", // 测试用例文件
supportFile: "tests/e2e/support/e2e.{js,jsx,ts,tsx}", // 配置全局注入
viewportHeight: 768, // 测试浏览器视口高度
viewportWidth: 1366, // 测试浏览器视口宽度 

之后就可以删掉cypress文件夹了,由于对cypress.config.js作了改动,所以需要重新启动Cypress来让配置生效

在这里事先将测试文件中的cy.visit("https://example.cypress.io")改成了cy.("/"),并运行npm run serve将项目跑起来,这样就可以对我们的新建项目进行测试了

可以看到运行npm run test:e2e后没任何问题🍻🍻🍻

E2E测试实践

下面我们就对打开的http://localhost:8080 页面进行测试。E2E测试旨在模拟用户真实的操作,确保应用在真实环境运行下一切正常工作,下面我们测试页面跳转的过程,测试内容有:

  • 当前页面h1的内容为Welcome to Your Vue.js App
  • 点击链接会跳转到Vue Cli官方文档,同时不打开新标签页
  • 在Vue Cli官方文档的输入框中输入@vue/cli-service

测试用例代码如下:

// tests/e2e/specs/first_e2e.cy.js

describe("tests vue2", () => {it("passes", () => {cy.visit("/"); // 访问默baseUrlcy.get("h1").should("contain", "Welcome to Your Vue.js App"); // 获取并断言h1内容cy.get('[data-test="vuecli"]').invoke("removeAttr", "target").click(); // 获取并点击vuecli链接cy.url().should("include", "cli.vuejs.org"); // 断言url内容cy.get("input").type("@vue/cli-service"); // 获取输入框并输入内容});
}); 
  • 这里为vuecli链接添加了data-test属性以方便在测试时选择,详细可以参考Best Practices
// HelloWorld.vue
...<adata-test="vuecli"href="https://cli.vuejs.org"target="_blank"rel="noopener">vue-cli documentation</a>
... 
  • 另外,上述标签的target属性值为_blank,所以会在新标签页打开链接,而Cypress由于其自动化测试的机制问题,是不支持多标签页测试的,因此在这里通过.invoke使用了jQueryremoveAttr方法,在点击前将 target属性去除,然后就可以在同一标签页打开新页面来进行测试
  • 除了cypress open,我们也可以运行cypress run命令,在不打开App的headless模式下进行测试,同时Cypress还会自动记录测试的整个过程,将视频和截图保存到配置的文件夹中,可自行在package.json中配置相关命令,这里我没配置,就直接在项目根路径下输入
npx cypress run --browser chrome // 指定运行环境为chrome浏览器 

记录的测试过程如下

遇到的问题

  • 安装Cypress后,运行npx cypress open时报错:No version of Cypress is installed in: C:\Users\ChenH\AppData\Local\Cypress\Cache\10.9.0\Cypress Please reinstall Cypress by running: cypress install 👉这是由于缺少执行文件,有两种方法来解决:先从download.cypress.io/desktop.jso… 下载对应版本的安装包,这里是v10.9.0* 方法1:自行解压缩后,CV到C:\Users\ChenH\AppData\Local\Cypress\Cache\10.9.0\Cypress下* 方法2:运行set CYPRESS_INSTALL_BINARY=d:\cypress.zip设置环境变量为该压缩包的路径,然后重新运行npm i cypress -D然后再运行npx cypress open就可以打开Cypress了* 运行E2E测试案例时报错Cypress detected a cross origin error happened on page load: > Blocked a frame with origin "http://localhost:8080" from accessing a cross-origin frame. 👉这是“同源策略”导致的,按照提示在cypress.config.js配置chromeWebSecurity: false就行参考资料

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值