你是否有以下烦恼:
当你加班加点完成一个功能后,提交给测试部,立马返回几个bug
当你修改完bug后,并检查了好几遍,确保无误后,提交给测试部,有返回几个bug
……
对于以上情境,你是否有过疑问,为什么检查都没问题了还是出现bug?以上这些都是因为没有做好测试。
你可能会问,做了呀,都检查好几遍了。的确,你是测试了,但是你并没有完成测试的闭环。你可能完成测试的一部分,其他的部分并没有完成。既然你说我没完成测试,那何为测试,又怎么进行测试?
对于前端来说,测试主要是对HTML、CSS、JavaScript进行测试,以确保代码的正常运行。
常见的测试有单元测试、集成测试、端到端(e2e)的测试。
既然知道了有这些测试种类,接下来就说说这些测试应当如何实现。
测试的方式可以分为人工测试、自动测试。
人工测试:就是让测试部的人员根据业务流程进行操作当某一步或几步出现问题就说明这部分代码有问题。这种测试方式有很明显的不足:
自动测试:利用写好的代码对代码进行测试。这种测试能够弥补人工测试的不足,它的颗粒度是代码级别的,能够准确地识别某个方法的错误
由此,在实际的开发过程中我们可以采用人工测试+自动测试的方式进行测试,力求100%的覆盖测试目标。人工测试暂且不谈,我们先谈谈自动测试的方式实现单元测试、集成测试、e2e测试。本篇博客先讲e2e测试。
实现e2e测试的库和框架有很多,这篇文章以Cypress为例进行讲解。
Cypress是基于JavaScript语言的前端自动化测试工具,无需借助外部工具,自集成了一套完整的端到端测试方法,可以对浏览器中运行的所有内容进行快速、简单、可靠的测试,并且可以进行接口测试
npm install cypress -D
安装完毕后,执行 npx cypress open
会打开一个窗口根据自己项目使用的框架和打包器进行选择,选择完毕后会自动生成配置文件及其相关文件,然后选择对应的测试类型,这里选择e2e测试。选择完毕后就可以运行测试套件。
对于vue项目来说,一般都会使用vue-router和vuex两个插件,因此在测试的时候需要把这两个插件挂载到vue实例上。
import {mount} from 'cypress/vue'
import router from '../../src/router';
Cypress.commands.add('mount',(component, options={})=>{
options.global.plugins = options.global.plugins || [];
options.global.component = options.global.component || {};
if(!options.router){
options.router = router;
}
options.global.plugins.add({
install(app){
app.use(options.router) ;
}
})
return mount(component,options);
})
import {mount} from 'cypress/vue'
import store from '../../src/store';
Cypress.commands.add('mount',(component,options={})=>{
options.global.plugins = options.global.plugins ||[];
options.global.component = options.global.component || {};
const {
store = store,
...mountOption,
} = options;
options.global.plugins.push({
install(app){
app.use(store);
}
});
return mount(component,mountOption);
})
import {mount} from 'cypress/vue'
import {BaseButton} from '../../src/components/BaseButton.vue'
Cypress.commands.add('mount',(component,options)=>{
options.global.component = options.global.component || {};
options.global.component.BaseButton = BaseButton;
return mount(component, options);
});
下面列举一些常用的配置项,具体配置说明访问配置说明
const {defineConfig} = require('cypress');
module.exports = defineConfig({
// e2e测试
e2e:{
},
// 组件测试
component:{
},
// 取消测试时录制视频
video:false,
// 取消测试失败时截屏
screenshotOnRunFailure:false
});
cypress框架的测试文件以.spec.js为后缀,测试时的目录可以通过cypress.config.js进行配置
mount()方法用于挂载组件
import HelloWorld from './HelloWorld.vue';
describe('description',()=>{
it('description',()=>{
cy.mount(HelloWorld);
});
});
cy.contains()方法用于检测页面中的元素的内容是否与指定的内容相同
it('测试 contains',()=>{
cy.contains('hello world');
});
cy.visit(url):访问url,只能访问返回html文件的url
cy.go():
cy.back():
cy.reload(boolean):true:不需要缓存,false:需要缓存
cy.url():获取网页的url
cy.title():获取网页的title
运行测试代码之后点击playground按钮用鼠标点击元素然后复制界面上方输入框的内容就可以得到一行代码。
within():在指定的元素中查找元素
cy.get('form').within((form)=>{
// 找form的第一个input
cy.get('input:first').type('username');
})
context():
cy.context()
children(selector):查找子元素
parent():获取元素的父元素
sibling():查找同级元素
prev():找到前一个元素
let pwd_el = cy.get('.username').sibiling('input');
pwd_el.prev('input');
next():找到下一个元素
let pwd_el = cy.get('.username').sibiling('input');
pwd_el.prev('input');
focus():输入框聚焦事件
cy.get('.password').focus().type('123');
blur():输入框失焦事件
cy.get('.username').blur();
submit():只有form表单才能调用
cy.get('.form').submit();
click():单击元素
dbclick():双击元素
rightclick():右击元素
check():选中单选框或多选框
cy.get('.radio').check();
cy.get('.checkbox').check();
// 强制选择,在禁用状态下依然可用
cy.get('.radio').check(true);
// 强制取消选择
cy.get('.radio').cehck(false);
// 选中其中的一个
cy.get('.checkbox').check('checkboxvalue');
cy.get('.radio').check('radiovalue');
// 选中其中的多个
cy.get('.checkbox').check('checkboxvalue1','checkboxvalue2');
select():选中下拉框的指定项
// 通过选项的value值选中选项
cy.get('.select').select('selectvalue');
// 通过选项的文本值选中选项
cy.get('.select').select('selectText');
// 选中多个
cy.get('.multipleSelect').select(['selectText1','selectText2'])
scrollIntoView():把元素滚动到可视范围内
scrollTo():滚动窗口到指定位置
cy.get('.input').scrollIntoView();
// 滚动到顶端
cy.scrollTo('top');
// 滚动到最底部
cy.scrollTo('bottom');
// 滚动到指定位置
cy.scrollTo(100,200)
如果你的项目中的html文件中有引入其他样式,那么在cypress/support/component-index.htmlz中也需要引入相同的样式。
如果你在项目中的main.js中引入其他样式,那么你在cypress/support/component.js中也需要引入相同样式。
例如,我的项目中使用view-ui-plus第三方组件库,引入了它的样式,那么在cypress/support/component.js中就需要引入该样式。
我的项目中的main.js文件
cypress文件夹下的component.js文件
在测试文件中,为组件提供一个props,props中注册事件名和事件响应函数
import Input from '../components/Input.vue'
describe('测试 input',()=>{
it('测试 change',()=>{
const changeHandler = (v)=>{
console.log(v);
}
cy.mount(Input,{
props:{
onChange:changeHandler
}
});
cy.get('.input').type('hello world');
cy.get('@onChange').should('have.been.calledWidth',1);
});
});