Next.js项目单元测试的配置(Jest+Enzyme)

2,352 阅读4分钟

背景

单元测试的重要性想必大家都知道,一方面可以比避免交接人修改导致的意料之外的错误,
一方面也有利于本身的开发流程,当我们的一个功能点不好写单元测试时,可能说明,
代码耦合度太高,需要重写。本文着重从使用的角度讲解一些,如何在一个中台项目中使用
单元测试。

书写单元测试的优缺点

优点:

  • 可读性:使测试用例覆盖我们的使用场景,方便我们重构,也比较我们修改代码后手动测试

  • 可维护性:交接项目的同事可以通过阅读测试用例更好的理解功能点的作用

缺点:

  • 我们可能会创建太多不必要的单元测试,以致于我们的项目变得难以维护

单元测试工具

使用的是Jest+enzyme的形式。

jest是js单元测试的框架,而Enzyme是一个基于jest的react组件测试工具库。

Jest 是 Facebook 开源的测试框架。它的功能很强大,包含了测试执行器、断言库、spy、mock、snapshot 和测试覆盖率报告等。

Enzyme 是 Airbnb 开源的 React 单元测试工具。它扩展了 React 官方的 TestUtils,通过类 jQuery 风格的 API 对 DOM 进行处理,减少了很多重复代码,可以很方便的对渲染出来的结果进行断言。

Jest is a JavaScript testing framework. Enzyme is a JavaScript testing utility for React that makes it easier to test your React Components’ output. Combine both of them, we will be able to implement testing on our project to make sure our code works as what we expected.

环境配置

可直接拉取项目代码参考 项目

我们暂且称项目为A,项目A使用的是 Nextjs+ts的技术栈,缺乏相关的参考文档,因此除了官网介绍的配置外,还需要增加ts相关的。我们从头来讲一下。

  • 安装jest相关依赖
npm install --save-dev jest babel-jest babel-core babel-preset-env babel-preset-react

安装enzyme 和 enzyme在react中使用所需依赖

npm install --save-dev enzyme enzyme-adapter-react-16
  • 安装依赖所需声明文件
npm install --save-dev typescript ts-jest @types/enzyme @types/enzyme-adapter-react-16 @types/jest
  • 配置jest 根目录下新建jest.config.js
module.exports = {
  preset: 'ts-jest',
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
  transform: {
    '^.+\\.tsx?$': 'ts-jest',
    '^.+\\.ts?$': 'ts-jest',
  },
  testMatch: ['**/*.(test|spec).(ts|tsx|js|jsx)'],
  globals: {
    'ts-jest': {
      babelConfig: true,
      tsConfig: 'jest.tsconfig.json',
      diagnostics: false,
    },
  },
  // transform: { '^.+\\\\.(css|less)$': './styleMock.js' },
  coveragePathIgnorePatterns: ['/node_modules/', 'setupTests.ts'],
  setupFilesAfterEnv: ['<rootDir>/setupTests.ts'],
  coverageReporters: ['json', 'lcov', 'text', 'text-summary'],
  moduleNameMapper: {
    '\\.(css|less|sass|scss)$': '<rootDir>/__mocks__/styleMock.js',
    '\\.(gif|ttf|eot|svg)$': '<rootDir>/__mocks__/fileMock.js',
  },
}

  • moduleNameMapper 用于指定mock tsx中import的less之类的文件,否则会出现报错
  • setupFilesAfterEnv 自定义jest启动入口文件的位置
  • ts-jest 在ts项目中使用jest的必须配置
  • testMatch 符合该规则的文件会被识别为测试文件

新建ts所需要的配置文件jest.tsconfig.json

{
    "compilerOptions": {
      "module": "commonjs",
      "target": "esnext",
      "jsx": "react",
      "sourceMap": false,
      "experimentalDecorators": true,
      "noImplicitUseStrict": true,
      "removeComments": true,
      "moduleResolution": "node",
      "lib": [
        "es2017",
        "dom"
      ],
      "typeRoots": [
        "node_modules/@types"
      ]
    },
    "exclude": [
      "node_modules",
      "out",
      ".next"
    ]
  }
  • jest使用ts的时候需要安装相关babel依赖
yarn add --dev @babel/preset-typescript
// babel.config.js/.babelrc
module.exports = {
  presets: [
    ['@babel/preset-env', {targets: {node: 'current'}}],
+    '@babel/preset-typescript',
  ],
};

配置Enzyme

新建 setupTests.ts

注意:这一步很多教程提供的文件名和新建文件的地址都有不同,原因是这个文件是定义在jest.config.js的setupTestFrameworkScriptFile的字段里面的,可以根据需要自定义~

import * as Enzyme from 'enzyme'
import * as Adapter from 'enzyme-adapter-react-16'

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

  • 在package.json文件中添加命令。
    "test": "jest",
    "test:watch": "jest — watch",
    "test:coverage": "jest — coverage"
  • 目前为止的目录结构
.
├── README.md
├── assets
├── commitlint.config.js
├── components
│   ├── Link
│   │   ├── __tests__
│   │   └── link.tsx
├── ecosystem.config.js
├── jest.config.js
├── jest.tsconfig.json
├── next-env.d.ts
├── next.config.js
├── package-lock.json
├── package.json
├── pages
│   ├── _app.tsx
│   ├── _document.tsx
│   └── pay
│       ├── index.tsx
├── pm2.config.js
├── postcss.config.js
├── server.js
├── setupTests.ts
├── stores
├── styles
├── tsconfig.json
├── yarn-error.log
└── yarn.lock
  • 实现一个简单的测试用例

根据刚才我们在jest.config.js中的定义,我们的测试文件后缀为ts,tsx,js,测试文件名称需要包含test/spec字段

一般情况下 我们在需要的组件下面新建__test__文件夹,书写测试用例,直接命令行跑npm run test就ok了

下面放个用于 测试的组件 作为demo

link.tsx
import * as React from 'react'

export default class extends React.Component<any, any> {
  constructor(props) {
    super(props)
  }

  render() {
    return <div>Hello Next.js</div>
  }
}

link.spec.js -- 单元测试
test('Jest-TypeScript 尝试运行', () => {
  expect(1 + 1).toBe(2) // Pass
})
组件测试
// link.spec.ts
import * as React from 'react'
import { shallow } from 'enzyme'

test('Jest-React-TypeScript 尝试运行', () => {
  const renderer = shallow(<div>hello world</div>)
  expect(renderer.text()).toEqual('hello world')
})

npm run test

效果,jest会匹配到所有的单元测试文件,并且执行测试用例,输出结果

总结

最后,送上我看到的一段话,书写单元测试可能对于刚开始的同学来说十四比较麻烦的,需要习惯上面的工具。但当我们习惯了,可以更轻松的code。

Some people might feel overwhelmed and it’s just a start. After finishing all those configurations, we still have to spend tons of time to get familiar with all the frameworks/libraries which have mentioned above. Although it will be tough at the beginning. But once we get familiar with them. It will definitely make coding much easier and also let us produce maintainable code.