一、环境安装
vue cli3 安装命令: vue add @vue/cli-plugin-unit-jest
配置文件 Jest.config.js
用例执行文件*.spec.js *.test.js
运行命令: yarn test:unit
"test:unit": "vue-cli-service test:unit ",
"test:unit-w": "vue-cli-service test:unit --watchAll",
"test:unit-u": "vue-cli-service test:unit --u",
二、使用方法
基础介绍
- Describe 用例分组
- It/test 用例执行方法
- expect().to** 匹配器,用于判断用例结果与预期结果是否相符
describe("分组描述2", () => {
it("toBe/toEqual", () => {
const a = { number: "007" };
expect(a).toBe(a);
expect(a).toEqual({ number: "007" });
});
});
常用匹配器
- toBe 严格匹配器 === expect(a).toBe({ age: ‘007’ })=>false
- toEqual 不严格匹配但要求值相等 expect(a).toEqual({ age: ‘007’ })=>true
- toBeNull 只匹配 null 不匹配 undeifined
- toBeUndifined toBeDefined
- toBeTruthy toBeFalsy
- toBeGreaterThan 大于 toBeGreaterThanOrEqual() 大于等于
- toBeLessThan 小于 toBeLessThanOrEqual()匹配器 小于等于
- toBeCloseTo 清除浮点精度错误的匹配器 expect(0.1 + 0.2).toBeCloseTo(0.3)
- toMatch 字符串包含匹配器 toContain 数组包含匹配器
- toThrow 检测一个方法是否抛出异常
- 官方文档:https://jestjs.io/docs/en/expect
钩子函数
- beforeAll()钩子函数 在所有测试用例之前进行执行
- afterAll() 钩子函数是 在所有测试用例完成之后才执行的函数
- beforeEach()钩子函数,在每个测试用例前都会执行一次的钩子函数
- afterEach()钩子函数, 在每次测试用例完成之后执行一次的钩子函数
分组作用域
- 钩子函数在父级分组可作用域子集,类似继承
- 钩子函数同级分组作用域互不干扰,各起作用
- 先执行外部的钩子函数,再执行内部的钩子函数
Mock 数据
- mockReturnValueOnce 设置一次函数的返回值
- mockImplementationOnce 设置一次可以在函数里面写更多的逻辑
- mockReturnValue mockImplementation 设置每次返回值
it(" 设置mockReturnValueOnce返回值", () => {
let fun = jest.fn();
fun.mockReturnValueOnce("123"); // 设置调用函数1次的返回值,设置几个就是几次
fun.mockReturnValueOnce("331");
fun.mockReturnValueOnce("33");
fun.mockReturnValue("666"); //设置每次调用函数的值都为666
expect(callbackFun(fun)).toBe("123");
expect(callbackFun(fun)).toBe("331");
expect(callbackFun(fun)).toBe("33");
expect(callbackFun(fun)).toBe("666");
});
it(" 设置mockImplementationOnce返回值", () => {
let fun = jest.fn();
// 设置调用函数1次的返回值
fun.mockImplementationOnce(() => {
return "123";
});
//设置每次调用函数的值都为666
fun.mockImplementation(() => {
return "666";
});
expect(callbackFun(fun)).toBe("123");
expect(callbackFun(fun)).toBe("666");
});
Mock 接口数据
jest.mock(‘axios’)模拟 axios 请求数据,不会发送真实请求(改变了 axios 函数内部实现) 不会真的去请求后台接口数据,使用模拟数据
import axios from "axios";
jest.mock("axios");
describe("axios", () => {
it("测试 getData,使用mock", async () => {
// 模拟第一次接收到的数据
axios.get.mockResolvedValueOnce({
data: { num: "123" },
});
// 模拟每一次接收到的数据
axios.get.mockResolvedValue({
data: "456",
});
const data1 = await getData();
const data2 = await getData();
console.log(data1);
expect(data1).toEqual({ num: "123" });
expect(data2).toBe("456");
});
});
异步
import axios from "axios";
function featchData2() {
return axios.get(
"https://bird.ioliu.cn/v2/?url=https://music.163.com/store/api/searchsuggest/get"
);
}
describe("异步", () => {
//错误示例
it("测试 featchData2", () => {
featchData2().then((res) => {
//测试data中是否包含code: 200
expect(res.data).toMatchObject({
code: 200,
});
});
});
// 当你使用done时,测试用例会一直等到执行到done()方法才结束
it("测试 1-featchData2", (done) => {
featchData2().then((res) => {
expect(res.data).toMatchObject({
code: 200,
});
done();
});
});
// // 如果返回的是一个 Promise 对象,可以直接使用 return 写法
test("测试 2-featchData2", () => {
return featchData2().then((res) => {
expect(res.data).toMatchObject({
code: 200,
});
});
});
// 如果返回的是一个 Promise 对象,可以直接使用 return + resolves/rejects 写法
test("测试 3-featchData2", () => {
return expect(featchData2()).resolves.toMatchObject({
data: {
code: 200,
},
});
});
// 第四种:如果返回的是一个 Promise 对象,async + await
test("测试 4-featchData2", async () => {
const results = await featchData2();
expect(results.data).toMatchObject({
code: 200,
});
});
});
Snapshot 快照测试
Snapshot 快照作用:把每次修改后的代码形成快照,与上次代码生成的快照做对比,若有修改部分,则会出现异常快照提示。
通过 yarn test:unit –u 更新快照
const generateConfig = () => {
return {
server: "http://localhost",
port: 1111,
domain: "localhost",
};
};
it("测试 generateConfig ", () => {
expect(generateConfig()).toMatchSnapshot();
});
行内 Snapshot
toMatchInlineSnapshot() 行内 Snapshot 把生成的快照放到了测试用例里边,作为第二个参数的形式传入。
toMatchSnapshot() 普通 Snapshot 会把生成的快照放到单独的文件里。
const generateAnotherConfig = () => {
return {
server: "http://localhost",
port: 80801111,
domain: "localhost",
time: new Date(),
};
};
test("测试 generateAnotherConfig ", () => {
expect(generateAnotherConfig()).toMatchInlineSnapshot(
{
time: expect.any(Date),
},
`
Object {
"domain": "localhost",
"port": 80801111,
"server": "http://localhost",
"time": Any<Date>,
}
`
);
});
Vue 组件
import navigationBar from "../../packages/navigation-bar/index.vue";
import { mount } from "@vue/test-utils"; //创建一个包含被挂载和渲染的 Vue 组件的 Wrapper
describe("vue", () => {
it("navbar", () => {
const wrapper = mount(navigationBar, {
// 通过 mount 生成了一个包裹器,包括了一个挂载组件或 vnode,以及测试该组件或 vnode 的方法
// 可以带参数, propsData 传递了接口数据
propsData: {
statusBarHeight: 45,
navigationBarHeight: 30,
},
slots: {
default: "<span>我家云</span>",
},
});
expect(wrapper.find("span").text()).toEqual("我家云");
});
});