单测(unit testing)
Jest
新建一个vue项目
vue create test-example
1、依赖安装
1、依赖安装vue-jest、Vue Test Utils、babel-jest、babel-preset-env
npm install --save-dev vue-jest Vue Test Utils babel-jest babel-preset-env
vue-jest:为了告诉 Jest 如何处理 *.vue 文件,我们需要安装和配置 vue-jest 预处理器
Vue Test Utils:官方vue测试辅助工具
babel-jest:在测试中让node支持es6转译
2、文件配置
scripts中添加测试命令
添加jest块,告诉jest要处理vue文件和遇到vue文件时候要使用vue-jest处理
// package.json
{
"scripts": {
"test": "jest"
}
}
// package.json
{
// ...
"jest": {
"moduleFileExtensions": [
"js",
"json",
// 告诉 Jest 处理 `*.vue` 文件
"vue"
],
"transform": {
// 用 `vue-jest` 处理 `*.vue` 文件
".*\\.(vue)$": "vue-jest"
}
}
}
如果你在 webpack 中配置了别名解析,比如把 @ 设置为 /src 的别名,那么你也需要用 moduleNameMapper 选项为 Jest 增加一个匹配配置:
{
// ...
"jest": {
// ...
// 支持源代码中相同的 `@` -> `src` 别名
"moduleNameMapper": {
"^@/(.*)$": "<rootDir>/src/$1"
}
}
}
配置支持babel
{
// ...
"jest": {
// ...
"transform": {
// ...
// 用 `babel-jest` 处理 js
"^.+\\.js$": "<rootDir>/node_modules/babel-jest"
}
// ...
}
}
完整package.json配置文件如下:
{
"name": "test-example",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:e2e": "vue-cli-service test:e2e",
"test:unit": "vue-cli-service test:unit",
"test": "jest"
},
"dependencies": {
"core-js": "^3.3.2",
"vue": "^2.6.10",
"vuex": "^3.0.1"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.0.0",
"@vue/cli-plugin-e2e-cypress": "^4.0.0",
"@vue/cli-plugin-unit-jest": "^4.0.0",
"@vue/cli-service": "^4.0.0",
"@vue/test-utils": "^1.0.0-beta.29",
"babel-jest": "^24.9.0",
"babel-preset-env": "^1.7.0",
"jest": "^24.9.0",
"vue-jest": "^3.0.5",
"vue-template-compiler": "^2.6.10"
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions"
],
"jest": {
"preset": "@vue/cli-plugin-unit-jest",
"moduleFileExtensions": [
"js",
"json",
"vue"
],
"transform": {
".*\\.(vue)$": "vue-jest",
"^.+\\.js$": "<rootDir>/node_modules/babel-jest"
},
"moduleNameMapper": {
"^@/(.*)$": "<rootDir>/src/$1"
}
}
}
测试vue组件实例
项目在git:https://github.com/lsx416010171/jest-example
import {mount} from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld'
import MyButton from '@/components/MyButton'
import Axios from '@/components/Axios'
import axios from 'axios'
describe('测试Vue组件实例',()=>{
// 创建一个包含被挂载和渲染的 Vue 组件的 Wrapper
const wapper = mount(HelloWorld)
it('测试props',()=>{
// 在创建的时候修改了props中msg的值
wapper.setProps({ msg: 'HelloWorld' })
expect(wapper.vm.msg).toBe('HelloWorld')
})
it('测试data',()=>{
// 使用setData来修改原组件data的值
wapper.setData({title : 'Im hello world in test'})
expect(wapper.vm.title).toBe('Im hello world in test')
})
it('测试DOM',()=>{
// 使用find来寻找dom中的元素
// text 是dom元素中文本的内容
expect(wapper.find('.hello h1').text()).toBe('HelloWorld')
// is 判断元素tag标签
expect(wapper.find('.hello h1').is('div'))
})
})
describe('测试Vue组件实例',()=>{
const wapper = mount(MyButton)
it('测试自定义事件',()=>{
// 创建mock函数
const mockFn = jest.fn();
// 设置 Wrapper vm 的方法并强制更新。
wrapper.setMethods({
increment: mockFn
});
// 模拟点击事件
wapper.find('button').trigger('click');
// 查看是否有回调
expect(mockFn).toBeCalled();
// 回调次数
expect(mockFn).toHaveBeenCalledTimes(1)
})
})
// 单元测试的核心之一就是测试方法的行为是否符合预期,在测试时要避免一切的依赖,将所有的依赖都mock掉。
// 第一步:不需要实际调用axios.get方法,需要将它mock掉
// 第二步:测试是否调用了axios方法(但是并不实际触发)并且返回了一个Promise对象
const mockData = {
data: {
code : 1,
msg : 'sucess'
}
};
jest.mock('axios', () => ({
get: jest.fn(() => Promise.resolve(mockData))
}));
describe('测试方法',()=>{
beforeEach(() => {
axios.get.mockClear();
wrapper = shallow(Axios);
});
// 点击按钮后调用了 getAnswer 方法
it('sendRequest Fn should be called', () => {
const mockFn = jest.fn();
wrapper.setMethods({sendRequest: mockFn});
wrapper.find('button').trigger('click');
expect(mockFn).toBeCalled();
});
// 点击按钮后调用了axios.get方法
it('axios.get Fn should be called', () => {
const URL = 'www.pokepe.vip/test';
wrapper.find('button').trigger('click');
expect(axios.get).toBeCalledWith(URL)
});
// 测试axios返回数据是否正确
// 因为axios是异步的,所以我们也要异步监听数据,有几种方法用来处理异步问题
// 1、done 2、async/await 3、Pomise
// done
// fetchData方法执行成功后,调用回调函数callback,遇到done才会结束
it('Calls get promise result',async ()=> {
function callback(data) {
expect(data).toBe('peanut butter');
done();
}
fetchData(callback);
});
// async/await 方法
it('Calls get promise result',async ()=> {
const result = await wrapper.vm.sendRequest()
expect(result).toEqual(mockData)
});
// axios.get方法返回值(Promise)
it('Calls get promise result', ()=> {
return expect(wrapper.vm.sendRequest()).resolves.toEqual(mockData);
});
})