前言
最近在看前端自动化测试相关的东西,在搭建环境的时候发现还是有许多需要注意的地方,而且网上很少有将各种测试(单元测试,集成测试,端对端测试)的环境搭建都提及的文章,对像我这样的新手不太友好,于是便打算删繁就简,希望通过这一篇文章能让大家对Vue
项目中自动化测试环境的搭建有个初步的认识,并且能够实现简单的测试用例,主要内容有:
- 单元测试环境搭建与案例实践(非浏览器环境)
- 使用
Jest
测试工具函数 - 使用
Jest
+Vue Test Utils
测试Vue
组件
- 使用
- 端对端测试环境搭建与案例实践(浏览器环境)
- 使用
Cypress
测试页面
- 使用
之所以没提及集成测试,是因为对前端而言,很难区分出单元测试和集成测试,普遍认为前端中的单元测试包括了集成测试,有关三种测试的区别,通过下面一张表希望能让大家对单元/集成/端对端测试有个初步的认识,感兴趣的可以继续了解一下测试金字塔和奖杯模型。
单元测试 | 集成测试 | 端对端测试 | |
---|---|---|---|
测试对象 | 代码单元(函数,模块等) | 组织在一起的代码单元 | 整个页面或应用 |
作用 | 保证代码单元在给给定输入下得到预期结果 | 保证多个模块组织在一起可以正常工作 | 模拟用户在真实环境中的操作,确保一切正常 |
测试环境 | 非浏览器环境 | 非浏览器环境 | 浏览器环境 |
代表工具 | Jest,Mocha,Karma等 | Jest, Testing Library等 | Cypress,Puppeteer, NightWatch等 |
本文所用的框架是vue2
,测试工具有Jest,Vue Test Utils和Cypress,选择它们的原因很简单:
图片来自于The State of JS 2021: 测试工具
好吧,其实是因为:
-
Jest👉All in one, 开箱即用
-
Vue Test Utils👉官网推荐
-
Cypress👉All in one, 开箱即用
在开始之前,我们需要有一个新的vue2
项目,这个相信大家有“手”(脚手架的手)就行,直接vue create first_test
。这里选择的是默认安装,也可以利用脚手架安装测试框架,但这不太现实,因为我们往往是对一个已有的项目进行测试,而不是在开发阶段就已经考虑到了测试🤣🤣🤣
接下来我们一起在一个已有项目(这里是vue2
新项目)中引入Jest
和Cypress
单元测试环境搭建与案例实践
安装 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.vue
和Child.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中:
- 当
showSpan
为true
时,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后
没任何问题🍻🍻🍻
下面我们就对打开的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("/"); // 访问默baseUrl
cy.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
...
<a
data-test="vuecli"
href="https://cli.vuejs.org"
target="_blank"
rel="noopener"
>vue-cli documentation</a>
...
- 另外,上述标签的
target
属性值为_blank
,所以会在新标签页打开链接,而Cypress由于其自动化测试的机制问题,是不支持多标签页测试的,因此在这里通过.invoke使用了jQuery
的removeAttr
方法,在点击前将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
👉这是由于缺少执行文件,有两种方法来解决:
先从https://download.cypress.io/desktop.json
下载对应版本的安装包,这里是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
就行
参考资料
快速入门 · Jest 中文文档 | Jest 中文网 (jestjs.cn)
Installation | Vue Test Utils (vuejs.org)
Writing Your First E2E Test | Cypress Documentation文章来源:https://www.toymoban.com/news/detail-598408.html
Front-End Testing is For Everyone | CSS-Tricks - CSS-Tricks文章来源地址https://www.toymoban.com/news/detail-598408.html
到了这里,关于一文,教你搭建前端自动化测试环境的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!