单元测试框架Jest学习总结
[[toc]]
测试框架
Mocha+chai
(断言库)
yarn add mocha chai -D
Jest
yarn add jest -D
适合场景
- 业务比较复杂
- 公司非常注重代码质量,想尽一切办法杜绝线上出bug
- 需要长期维护的项目。它们需要测试来保障代码可维护性、功能的稳定性
- 被多次复用的部分,比如一些通用组件和库函数。因为多处复用,更要保障质量
- 开源项目
首先安装需要的包
基于vue
yarn add jest vue-jest babel-jest @vue/test-utils @types/jest -D
|
注意版本号之间兼容性问题
让Jest支持ES6语法
"@babel/preset-env", { "targets": { "browsers": [ "chrome >= 50" ], "node": "current" }, "modules": "auto" }
|
测试的步骤
- 写测试说明,针对你的每条测试说明测试了什么功能,预期结果是什么。
- 写测试主体,通常是 输入 -> 输出。
- 判断测试结果,拿输出和预期做对比。如果输出和预期相符,则测试通过。反之,不通过。
yarn add jest @types/jest babel-jest babel-core babel-preset-env regenerator-runtime -D
Jest本身是不支持es6的,但是在react中已经配置好babel等,可以直接使用ES6的语法特性进行单元测试
使用方式
toBe()
绝对相等
toEqual()
判断对象或者数组是否相等
toBeNull()
只匹配null
toContain()
检测数组中是否包含特定某一项
toBeUndefined()
只匹配undefined
toBeDefine()
与toBeUndefined相反
toBeTruthy()
匹配任何if语句为真
toBeFalsy()
匹配任何if语句为假
toBeCloseTo(0.3)
浮点数判断相等
数字匹配器
toBeGreaterThan()
大于
toBeGreaterThanOrEqual()
大于或者等于
toBeLessThan()
小于
toBeLessThanOrEqual()
小于或等于
package里面关于jest的配置
"scripts": { "test": "jest", "app":"jest /test/app.test.js --watch" "test-watch": "jest --watchAll", "test-with-coverage": "jest --coverage" }, "jest": { "collectCoverage":true, "collectCoverageFrom": [ "src/**/*.{js,jsx,ts,tsx}", "!src/**/*.d.ts" ], "coverageDirectory": "tests/coverage", "resolver": "jest-pnp-resolver", "setupFiles": [ "react-app-polyfill/jsdom" ], "testMatch": [ "<rootDir>/test/**/__tests__/**/*.{js,jsx,ts,tsx}", "<rootDir>/test/**/?(*.)(spec|test).{js,jsx,ts,tsx}" ], "testEnvironment": "jsdom", "testURL": "http://localhost", "transform": { "^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest", "^.+\\.css$": "<rootDir>/config/jest/cssTransform.js", "^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js" }, "transformIgnorePatterns": [ "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$", "^.+\\.module\\.(css|sass|scss|less)$" ], "moduleNameMapper": { "^react-native$": "react-native-web", "^.+\\.module\\.(css|sass|scss|less)$": "identity-obj-proxy", "^@(.*)$": "<rootDir>/src$1" }, "moduleFileExtensions": [ "js", "ts", "tsx", "json", "jsx", "node" ] }
|
Jest.config.js
module.exports = { moduleFileExtensions: ["vue", "js", "jsx"], testEnvironment: "jsdom", transform: { "^.+\\.js$": "babel-jest", "^.+\\.vue$": "vue-jest", }, moduleDirectories: ["node_modules"], testRegex: "(/__tests__/.(js|jsx)|(\\.|/)(test|spec))\\.(js|jsx)$", moduleNameMapper: { "^@/(.*)$": "<rootDir>/src/$1", }, };
|
代码覆盖率
可以查看你那些代码没有被覆盖,帮助你发现盲点
- 在命令行中通过 “–coverage” flag 指定
- 在 package.json 中手动配置
%stmts是语句覆盖率(statement coverage):是不是每个语句都执行了?
%Branch分支覆盖率(branch coverage):是不是每个if代码块都执行了?
%Funcs函数覆盖率(function coverage):是不是每个函数都调用了?
%Lines行覆盖率(line coverage):是不是每一行都执行了?
Uncovered Line 是哪行没有被覆盖
专业术语里,把describe包含的块叫做suite,把it/test包含的块叫做specification,也简称为spec,在一个suite里面可以包含多个数量的spec,但是也要注意结构化语义化。
示例
编写测试文件时遵循的命名规范:测试文件的文件名
= 被测试模块名
+ .test.js
import axios from 'axios'; export default { fetchUser() { return axios.get('http://jsonplaceholder.typicode.com/users/1') .then(res => res.data) .catch(error => console.log(error)); }, sum(a, b) { return a + b; } }
import functions from '../src/functions'; test('fetchUser() 可以请求到一个含有name属性值为Leanne Graham的对象', () => { expect.assertions(1); return functions.fetchUser() .then(data => { expect(data.name).toBe('Leanne Graham'); }); }); it('fetchUser() 可以请求到一个含有name属性值为Leanne Graham的对象 async -- await', async () => { expect.assertions(1); const data = await functions.fetchUser();
expect(data.name).toBe('Leanne Graham');
}); describe('加法函数测试', () => { it('1加2应该等于3', () => { expect(functions.sum(1, 2)).toBe(3); }); }); test('sum(2 + 2) 等于 4', () => { expect(functions.sum(2, 2)).toBe(4); }); test('sum(2 + 2) 等于 4', () => { expect(functions.sum(2, 2)).not.toBe(1008611); }); test('there is no I in team', () => { expect('team').not.toMatch(/I/); }); test('but there is a “stop” in Christoph', () => { expect('Christoph').toMatch(/stop/); }); test('测试浮点数是否相等', () => { expect(0.003 + 0.01).toBeCloseTo(0.013); }); test('对象判断是否相等', () => { expect({test: "11111"}).toEqual({test: "11111"}); });
describe("筛选数组", () => { test("it should filter by a search term (link)", () => { const input = [ {id: 1, url: "https://www.url1.dev"}, {id: 2, url: "https://www.url2.dev"}, {id: 3, url: "https://www.link3.dev"} ];
const output = [{id: 3, url: "https://www.link3.dev"}];
expect(filterByTerm(input, "link")).toEqual(output);
expect(filterByTerm(input, "LINK")).toEqual(output); }); });
function filterByTerm(inputArr, searchTerm) { const regex = new RegExp(searchTerm, "i"); const a = inputArr.filter(function (arrayElement) { return arrayElement.url.match(regex); }); console.log(a); return a }
|
vue中的测试案例
<template> <div> <slot></slot> </div> </template>
// test.spec.js import { shallowMount, mount } from "@vue/test-utils"; import test from "../test.vue"; import Vue from "vue";
describe("test.vue", () => { let wrapper = shallowMount(test, { slots: { default: "测试案例", }, });
it("设置slot", () => { return Vue.nextTick().then(function() { expect(wrapper.text()).toBe("测试案例"); }); }); });
|
未完待续…
参考文档
*ReactTestUtils
参考文档
参考文档2
jest 别名
Jest 入门教程