最近折腾了单测,体会比较多,将思考、总结记录在这里,留作念想。

开篇

单测这件事情,感觉不是佛系的,要分场合,项目里有些复杂的utils、工具库、组件库是要有单测支撑的。
提倡单测的理由如下:

  • 写代码之前先写用例case,可以让我们好好设计接口、模块、明确数据流向和上下游的关系
  • 增强提测、上线质量

业务组件添加单测是锦上添花的事情,而且,学点新的知识有什么不好呢。单测的框架有不少,今天看看vue-test-utils,它是vue组件的官方测试库,内部使用了Facebook推出的Jest测试框架
官方文档:
https://lmiller1990.github.io/vue-testing-handbook/zh-CN/
https://jestjs.io/zh-Hans/docs/getting-started

安装开发环境

vue-cli配套插件@vue/cli-plugin-unit-jest, @vue/test-utils等可提供jest环境,依照项目实际情况修改jest配置

  1. module.exports = {
  2. // 哪些文件是要进行测试的
  3. testMatch: [
  4. '**/tests/**/*.spec.js',
  5. ],
  6. // 预置,是解析的意思???
  7. preset: '@vue/cli-plugin-unit-jest',
  8. // ....等
  9. }
  1. scripts: {
  2. "unit": "vue-cli-service test:unit",
  3. "unit:dev": "vue-cli-service test:unit --watchAll",
  4. }

还有vscode的神辅助插件

  • Jest

对于整个项目的文件提供基本测试条件,如项目开启就自动监听变化,如果觉着造成不必要的浪费,可以手动关掉

  • Jest Runner

方便我们测试和调试单个文件,Jest Runner使用的调试工具就是VScode的调试,所以启动的都是node环境,适当的时候要修改下babel.config.js的配置,否则会报错,比如不识别import等
至于为何运行npm run unit就不会报错,我猜测可能因为vue的sever服务帮我们做了一步转换吧

  1. presets: [
  2. [
  3. '@babel/preset-env',
  4. {
  5. targets: {
  6. node: 'current',
  7. },
  8. },
  9. ],
  10. ]
  1. {
  2. // jest debug配置
  3. "jestrunner.debugOptions": {
  4. "args": ["--no-cache"],
  5. "sourcemaps": "inline",
  6. "disableOptimisticBPs": true
  7. },
  8. // 不允许启动就开启单测监听模式
  9. "jest.autoRun": "false",
  10. "jestrunner.jestPath": "node_modules/jest/bin/jest.js",
  11. "jestrunner.jestCommand": "npm run unit --",
  12. }
  13. // 具体关于这个写法(究竟叫什么名字)请调出插件的具体信息

image.png

具体的测试用例

下面以2个具体的例子来说明,一个是简单一些的util api测试,一个是公共组件的组件测试。
单测具体有两部分组成:

  1. import { isNumber } from './util.js'
  2. describe('test isNumber', () => {
  3. test('是一个数字', () => {
  4. expect(isNumber(8)).toBe(true);
  5. })
  6. // test vs it
  7. it('ccc', () => {
  8. })
  9. })

在一个组件里面如果涉及到api请求、vuex store、vue router、等都有解决方案,可以通过mock创造你想要的绝大多数功能。
其中以mock api为例:

  1. import request from './request.js'
  2. // jest.mock('./request.js'); 就可以直接mock函数
  3. // 其中request调用axios,是自己封装的一个请求库
  4. <button @click="submit">提交</button>
  5. function submit() {
  6. request({
  7. url: 'xxx',
  8. data: {}
  9. })
  10. }

注意事项

expect(运行结果).toBe(期望的结果)
常见的断言方法:

  1. expect({}).toBe({}) //判断两个对象是否相等
  2. expect().not.toBe()
  3. expect().toEqual() // 判断引用对象是否相等
  4. expect(n).toBeNull(); //判断是否为null
  5. expect(n).toBeUndefined(); //判断是否为undefined
  6. expect(n).toBeDefined(); //判断结果与toBeUndefined相反
  7. expect(n).toBeTruthy(); //判断结果为true
  8. expect(n).toBeFalsy(); //判断结果为false
  9. expect(value).toBeGreaterThan(3); //大于3
  10. expect(value).toBeGreaterThanOrEqual(3.5); //大于等于3.5
  11. expect(value).toBeLessThan(5); //小于5
  12. expect(value).toBeLessThanOrEqual(4.5); //小于等于4.5
  13. expect(value).toBeCloseTo(0.3); // 浮点数判断相等
  14. expect('Christoph').toMatch(/stop/); //正则表达式判断
  15. expect(['one','two']).toContain('one'); //不解释

jest的实现原理是什么呢?

敬请期待