Unit Testing

2022-04-01 16:07:41 浏览数 (1)

前言

Jest 是 Facebook 推出的一种 Unit Testing 工具,当然还有很多其他类似的单元测试库,比如 mocha ava 等等

写的好的单元测试可以帮助你提升开发效率以及代码质量,并对项目的维护有莫大的帮助,例如重构。

#应该测试你的程序

其实每一个项目都应该使用单元测试,单元测试可以很好的保证你的代码不会欺骗你

世界上没有任何一个完美的程序,也更不会有完美的人可以写出没有任何问题的代码。

#配置单元测试

#安装 Jest

我们使用 yarn 来安装 Jest

代码语言:javascript复制
yarn add -D jest

package.json 文件中加入测试命令

代码语言:javascript复制
{
  "scripts": {
    "test": "jest"
  }
}

之后只需要在 Command Line 中输入 yarn test 即可开启测试

#配置时遇到的麻烦

在我配置 Jest 时遇到了几个麻烦,让我的测试代码运行不起来,总结一下这几个小问题。

  1. 运行 Jest 测试代码时出现 Cannot use import statement outside a module

不能在其他模块使用 import 语句

出现这个问题的主要原因在于 Webpack 编译时并未转换 Jest,导致测试代码不识别 ES6 语法,需要配置一下 Jest 的 transform 字段

JS 代码,需要安装 babel-jest 包来转换代码

代码语言:javascript复制
transform: {
  "^. \.js?(x)?$": "babel-jest"
}

TS 代码,需要额外安装一个 ts-jest 包来解析

代码语言:javascript复制
transform: {
  "^. \.(ts|tsx|js)$": "ts-jest"
}
  1. 在项目中配置了别名。但是 Jest 并不认识别名

这个问题大概都会遇到吧,几乎在项目中都会有 Webpack 来做别名处理,解决那种点点引用方式,例如:

代码语言:javascript复制
// 点点表示法
import SomeComponent from '../../../../components/SomeComponent'

// 别名表示法
// @ 代表 src/ 目录
import SomeComponent from '@/components/SomeComponent'

jest.config.js 文件中配置 moduleNameMapper 字段即可

代码语言:javascript复制
{
  moduleNameMapper: {
    '@/(.*)$': '<rootDir>/src/$1'
  }
}

用来匹配 @/ 都指向到 根目录/src/前文中(.*)`匹配的分组

  1. 未忽略 node_modules 文件夹下的代码

一般来说这个是默认的,Jest 默认会忽略 node_modules 文件夹下的文件和代码

  1. 无法识别 css scss 等样式文件

在我们组件当中大部分都会有 css 或者 scss 等文件,但是 Jest 并无法处理这类文件,此时需要将此类样式文件都 Mock

代码语言:javascript复制
{
  moduleNameMapper: {
    '\.(css|scss)$': '<rootDir>/__mocks__/styleMock.js'
  }
}

<rootDir>/__mocks__/styleMock.js 文件代码

代码语言:javascript复制
module.exports = {}
  1. 如果要使用 Enzyme 辅助库的话,需要额外配置一下

配置 setupFiles 字段,该字段的含义是在初始化运行单元测试时,需要执行的文件

代码语言:javascript复制
{
  setupFiles: ['<rootDir>/__mocks__/enzymeMock.js']
}

<rootDir>/__mocks__/enzymeMock.js 文件代码

代码语言:javascript复制
import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-16'

Enzyme.configure({ adapter: new Adapter() })

其他配置可以参考官网的配置文档来进行进一步的配置

#如何做好单元测试

#一个好的单元测试应该遵循下面三个步骤

代码语言:javascript复制
// production code
const computeSumFromObject = (a, b) => {
  return a.value   b.value
}

// testing code
it('should return 5 when adding object a with value 2 and b with value 3', () => {
  // given - 准备数据
  const a = { value: 2 }
  const b = { value: 3 }

  // when - 调用被测函数
  const result = computeSumFromObject(a, b)

  // then - 断言结果
  expect(result).toBe(5)
})

Given -> When -> Then

准备输入数据、调用被测函数、断言输出结果。

#一个好的测试可以为我们带来什么

  • 安全重构已有代码 -> 当你在重构当前代码时,完全不必担心会损坏其功能
  • 保存业务原有逻辑 -> 只要 PM 没有改动需求,这个需求就应该是这样的,如果测试代码出了问题,那么一定是你出了问题
  • 快速回归 -> 当我们在开发业务的时候,例如在原有功能上添加新的功能,那么新开发的功能不会影响之前业务的逻辑,如果测试代码出了问题,那么一定是你的问题

#测试覆盖率

在真实的项目开发当中,我们其实并不会对项目中所有的代码进行测试。本来单元测试带来的收益是你在走独木桥时,他将是你的安全带。但是如果你将所有的代码都写了单元测试,那么我觉得你是把全身的安全带都绑上了,只露了一只眼睛,你的开发工作将举步难行,下面来说说单元测试应该覆盖哪些,不应该覆盖哪些

组件类型/测试内容

分支渲染逻辑

事件调用

纯 UI

展示型组件

容器型组件

通用 UI 组件

功能型组件

总结一句话就是,所有的功能型代码,都需要进行单元测试,但是像 UI 以及 css 等样式代码,就不要进行不必要的测试了,意义其实并不大,除非你要写像 Ant Design 这类的 UI 库,在日常的业务场景下是完全没有必要。

在表格中 ✅ 的,建议是在 100% 的覆盖率

#参考

  1. Jest
  2. React 测试技巧
  3. React 单元测试策略及落地
  4. 单元测试-维基百科

0 人点赞