单元测试框架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 入门教程