vue 中的单元测试
一、背景
随着项目越来越大,复杂度上升,改动一个地方,可能造成连环反应,引发未知 bug
我们需要在保证项目稳定的情况下,进行开发
这里选择 jest 作为测试框架
配置少,功能完善
二、安装与配置
1、安装 jest、@vue/test-utils
jest: 测试框架
@vue/test-utils: vue 测试工具,用来提供包裹 vue 组件,并暴露一些用来操作组件的方法和属性
yarn add jest @vue/test-utils -D
2、在 package.json 中添加 script 命令
{
"script": {
"test": "jest" // 在 node 环境中运行 jest 命令
}
}
3、安装 vue-jest 处理 vue 文件
yarn add vue-jest -D
添加 jest 配置文件 jest.config.js
// webpack 是支持 ES modules的,所以默认不开启 ES modules 转译
// 这里要设置开启 ES modules 转译,因为 node 环境不一定支持新特性
process.env.VUE_CLI_BABEL_TARGET_NODE = true
process.env.VUE_CLI_BABEL_TRANSPILE_MODULES = true
module.exports = {
// 告诉 jest 处理 js、jsx、json、vue 文件
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
// 告诉 jest 使用 vue-jest 处理 vue 文件
transform: {
'.*\\.(vue)$': 'vue-jest'
},
// jest 默认忽略对 node_modules 的转换解析,我们项目中有使用到 vant 等包,所以不能忽略
// 这里随便写一个资源路径进行覆盖
transformIgnorePatterns: ['/src/assets'],
// 告诉 jest 关于 webpack 中的别名解析
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1' // 对应 @ ---> src
},
// snapshotSerializers: ['jest-serializer-vue'],
// 启动测试命令时,自动寻找匹配文件执行
testMatch: [
'**/test/**/*.test.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
]
// testURL: 'http://localhost/',
// watchPlugins: [
// 'jest-watch-typeahead/filename',
// 'jest-watch-typeahead/testname'
// ]
}
4、安装 babel-jest
测试代码可能使用了很多新的语法特性
因为是跑在 node 环境中,node 可能并不支持
所以要使用 babel-jest 在运行代码前来进行转换
yarn add babel-jest -D
在 jest.config.js 中 transform 属性添加配置
module.exports = {
// 告诉 jest 使用 babel-jest 处理 js 文件
transform: {
'^.+\\.js$': 'babel-jest'
}
}
5、安装 jest-transform-stub
解析到静态资源如图片、样式表时使用 jest-transform-stub 处理
jest-transform-stub 实际是返回一个空字符串,因为测试时并不需要这些资源
yarn add jest-transform-stub -D
在 jest.config.js 中 transform 属性添加配置
module.exports = {
// 告诉 jest 使用 jest-transform-stub 处理静态资源
transform: {
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
'jest-transform-stub'
}
}
6、放置测试文件
默认情况下 jest 会递归查找整个项目中所有的 .spec.js 和 .test.js 扩展名的文件
推荐在测试目录下创建一个 __test__
目录,放置测试文件
7、eslintrc.js
在 env 中加入 jest,让 eslint 识别 jest 全局变量
{
env: {
jest: true
}
}
三、使用
思考测试逻辑
// 一开始不知道要测试什么,怎么测试
// 我们可以把需要测试的情况罗列出来,然后一一编码,先思考后动手
// 1、issuerName 1、截取18个字符 2、没有值时为'--'
// 2、h2Style 1、发行人+标签长度如果大于22,则改变字体大小
// 3、limitTags 1、最多截取三个标签 2、没有值时为[]
// 4、buyYtm 1、精确到小数后3位 2、没有值时为'--'
// 5、paymentFrequency 1、有值时后续加上'付息' 2、没有值时位'--'
// 6、paymentDates 1、付息日超过2个(不包含)则在后面加上'等',并且只截取前两个展示 2、没有值时为'--'
取值对比方式
// Q:直接使用 wrapper.vm 获取数据进行对比还是取页面上展示的文本进行对比?
// A:我比较倾向于第二种,取页面上展示的文本进行对比
// 组件中可能因为各种原因,不敢修改之前的变量数据。
// 此时新增变量替换原先模板中的变量,页面上展示改变了,但是脚本中原有变量还在,测试正常通过,这是不对的
// 所以应该以实际页面展示为准。
// 只有在页面上无法测试到的时候,直接拿 wrapper.vm 上的数据对比
方法
1、构造输入值
2、传入`构造输入值`给要测试的方法, 并执行
3、对比测试执行方法`返回的结果/产生的影响`与预期的是否一样
util 测试
如果引入了依赖包,jest 找不到,需要在 jest.config.js 中的 moduleNameMapper 配置依赖包的解析路径
moduleNameMapper: {
'^dayjs$': '<rootDir>/node_modules/dayjs'
}
window.location.href 需要在 jest.config.js 中的
testURL: 'http://www.baidu.com?test1=123&test2=321'
自定义日期对象方法,可以测试倒计时类似的方法
let t1 = new Date('2020-05-15').getTime()
let t2 = new Date('2022-05-15').getTime()
let initTime = new Date('2019-10-18').getTime()
Date.prototype.getTime = function() {
return initTime
}
props 测试
const wrapper = mount(component, {
propsData: {
}
})
wrapper.props()
wrapper.props('key')
以下待补充~~~~
state 测试
mutation 测试
action 测试
API 调用测试
mock 数据走完流程
都读到最后了、留下个建议如何