vue+jest
在创建项目时自定义选择test unit,再次询问时选择jest
自动生成jest.config.js配置文件,test/unit文件夹,文件夹内有一个helloWorld的示例测试文件。
在package.json中会生成 “test:unit”: “vue-cli-service test:unit”,命令,npm run test:unit运行jest的测试用例。
配置项
在jest.config,js中配置
module.exports = {
//自动生成仅有present一个配置项
preset: "@vue/cli-plugin-unit-jest",
// 告诉jest需要解析的文件
moduleFileExtensions: ["js", "vue", "json"],
// 开启测试报告
// collectCoverage: true,
// 统计哪里的文件
// collectCoverageFrom: ["**/src/components/**", "!**/node_modules/**"],
// 告诉jest去哪里找模块资源,同webpack中的modules
// moduleDirectories: [
// 'src',
// 'node_modules'
// ],
// 告诉jest针对不同类型的文件如何转义
// transform: {
// '^.+\\.(vue)$': '<rootDir>/node_modules/vue-jest',
// '^.+\\.js$': '<rootDir>/node_modules/babel-jest',
// '.+\\.(css|style|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
// '^.+\\.jsx?$': 'babel-jest',
// '^.+\\.ts?$': 'ts-jest'
// },
// 告诉jest在编辑的过程中可以忽略哪些文件,默认为node_modules下的所有文件
// transformIgnorePatterns: [
// '<rootDir>/node_modules/'
// + '(?!(vue-awesome|veui|resize-detector|froala-editor|echarts|html2canvas|jspdf))'
// ],
// 别名,同webpack中的alias
// moduleNameMapper: {
// '^src(.*)$': '<rootDir>/src/$1',
// '^@/(.*)$': '<rootDir>/src/$1',
// '^block(.*)$': '<rootDir>/src/components/block/$1',
// '^toolkit(.*)$': '<rootDir>/src/components/toolkit/$1'
// },
// snapshotSerializers: [
// 'jest-serializer-vue'
// ],
// 告诉jest去哪里找我们编写的测试文件
// testMatch: [
// '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
// '**/tests/unit/**/Test.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
// ],
// 在执行测试用例之前需要先执行的文件
// setupFiles: ['jest-canvas-mock']
};
vsCode安装jest插件,这个插件会自动在每次保存代码时执行以spec.js为结尾的文件,当函数不满足用例条件时会将用例匹配器比较的部分标红,方便快速定位问题部分。
对组件及组件内的函数进行测试
<!-- Counter组件 -->
<template>
<div>
<div>{{ computedCount }}</div>
<button @click="inc">加</button>
<button @click="dec">减</button>
<button @click="reset">重置</button>
</div>
</template>
<script>
export default {
props: {
factor: { type: Number, default: 1 },
},
data() {
return {
count: 2,
};
},
methods: {
inc() {
this.count++;
},
dec() {
this.count--;
},
reset() {
this.count = 2;
},
},
computed: {
computedCount: function () {
return this.count * this.factor;
},
},
};
</script>
//Counter.spec.js文件,文件位置test/unit
import { mount } from "@vue/test-utils";
//mount表示挂载组件及其子组件,shallowMount表示仅挂载组件,不挂载其子组件
//组件测试需要先引入组件
import Counter from "@/components/Counter.vue";
//分组测试
describe("Counter.vue", () => {
//wrapper: 一个 wrapper 是一个包括了一个挂载组件或 vnode,以及测试该组件或 vnode 的方法。
//wrapper.vm: 可以访问一个实例所有的方法和属性
//wrapper.setData() : 同Vue.set()
//wrapper.trigger(): 异步触发事件
//wrapper.find(): 返回DOM节点或者Vue组件
it("渲染Counter组件", () => {
const wrapper = mount(Counter);
//toMatchSnapshot快照测试,第一次运行会在test/unit/_snapshot中生成一个快照文件,
expect(wrapper.element).toMatchSnapshot();
});
//expect匹配器,后跟toBe或其他函数匹配规则
it("初始化之为2", () => {
const wrapper = mount(Counter);
//wrapper.vm可以访问组件实例中的所有属性和方法
expect(wrapper.vm.count).toEqual(2);
});
//推荐使用toEqual,除非需要确保验证对象与内存完全一样,这时使用toBe
it("加1", () => {
const wrapper = mount(Counter);
//调用一次增加count的方法
wrapper.vm.inc();
//验证调用此方法后的count值
expect(wrapper.vm.count).toEqual(3);
});
it("减1", () => {
const wrapper = mount(Counter);
wrapper.vm.dec();
expect(wrapper.vm.count).toEqual(1);
});
it("重置", () => {
const wrapper = mount(Counter);
wrapper.vm.reset();
expect(wrapper.vm.count).toEqual(2);
});
it("因数为10加1操作", () => {
const wrapper = mount(Counter, { propsData: { factor: 10 } });
//调用一次增加count的方法
wrapper.vm.inc();
//验证调用此方法后Counter组件计算属性的值
expect(wrapper.vm.computedCount).toEqual(30);
});
});
Counter组件的快照
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Counter.vue 渲染Counter组件 1`] = `
<div>
<div>
2
</div>
<button>
加
</button>
<button>
减
</button>
<button>
重置
</button>
</div>
`;
对js文件内的方法进行测试
//在sum.js里我定义了两个方法,sum和add
//在sum.spec.js中将两个方法从sum.js文件引入,再对这两个方法进行单元测试
test("adds 1 + 2 to equal 3", () => {
expect(sum(1, 2)).toEqual(3);
});
test("测试add数组函数,参数-->[参数]", () => {
expect(add(1)).toContain(1);
});
//对异步请求进行测试
test("异步测试", async () => {
expect.assertions(1);
undefined;
const response = await axios.get(
"http://www.dell-lee.com/react/api/demo.json"
);
//请求返回值:{"success": true}
expect(response.data).toEqual({
success: true,
});
});
//使用rejects判断异常
test("测试异常", async () => {
undefined;
await expect(
axios.get("http://www.dell-lee.com/react/api/demo1.json")
).rejects.toThrow();
});
jest提供了几个类似生命周期的钩子函数
// 全部测试前执行
beforeAll(() => {
undefined;
// 逻辑
});
// 每次测试前执行
beforeEach(() => {
undefined;
// 逻辑
});
// 全部测试后执行
afterAll(() => {
undefined;
// 逻辑
});
// 每次测试后执行
afterEach(() => {
undefined;
// 逻辑
});
// 分组测试
// describe("描述", () => {
// undefined;
// 测试案例...
// test();
// });
jest测试用例常用的几个匹配器
// toEqual/toBe 匹配值相等,比较浮点数时必须使用toBeCloseTo
expect(a).toEqual(b)
// toBeNull 匹配 null
expect(a).toBeNull()
//toBeUndefined 匹配 undefined
expect(a).toBeUndefined()
//toBeDefined 是否定义
expect(a).toBeDefined()
//toBeTruthy 是否为true
expect(a).toBeTruthy()
//toBeFalsy 是否为false
expect(a).toBeFalsy()
// not 匹配器 (取反)
expect(a).not.toBeFalsy()
//toBeGreaterThan 匹配 数字大小 a > b
expect(a).toBeGreaterThan(b) //toBeGreaterThanOrEqual 匹配数字大小 a >= b
//toBeLessThan 匹配 数字大小 a < b
expect(a).toBeLessThan(b)
// toBeLessThanOrEqual 匹配数字大小 a <= b
// toBeCloseTo 小数近似,期望差异默认为小于0.005,超出这个差值即认为不是小数近似,可加入第二个参数设置差异精度,不设置默认为2即0.005,第二个参数越大精度范围越小,可设置为负数
it("小数近似", () => {
const a = 123;
const b = 124;
expect(a).toBeCloseTo(b, -1);
});
//toMatch 匹配 字符串,比较是正则比较,验证a中是否包含有b,如果包含就会通过,如
/*it("字符串匹配", () => {
const a = "123z";
const b = "123";
expect(a).toMatch(b);
});
a和b用toMatch进行比较是可以通过验证的,但如果a=12a3z就不会通过
**/
expect(a).toMatch('string')
// toContain 数组匹配,验证数组中是否含有该元素,进行删除操作时可以在toContain前加not;取反验证
expect(arr).toContain(obj)
test("测试add数组函数,参数-->[参数]", () => {
expect(add(1)).toContain(1);
});
// 异常检测
expect(fn).toThrow()