关于前端:react-项目单元测试技术方案

8次阅读

共计 3700 个字符,预计需要花费 10 分钟才能阅读完成。

Why

The more your tests resemble the way your software is used, the more confidence they can give you.

背景

该我的项目是用 umi 框架搭建,其本身内置了 jest 测试框架

  • umi 内置的 jest 配置
{
    collectCoverageFrom: ['index.{js,jsx,ts,tsx}',
      hasSrc && 'src/**/*.{js,jsx,ts,tsx}',
      isLerna && !args.package && 'packages/*/src/**/*.{js,jsx,ts,tsx}',
      isLerna &&
        args.package &&
        `packages/${args.package}/src/**/*.{js,jsx,ts,tsx}`,
      '!**/typings/**',
      '!**/types/**',
      '!**/fixtures/**',
      '!**/examples/**',
      '!**/*.d.ts',
    ].filter(Boolean),
    moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json'],
    moduleNameMapper: {'\\.(css|less|sass|scss|stylus)$': require.resolve('identity-obj-proxy'),
    },
    setupFiles: [require.resolve('../../helpers/setupFiles/shim')],
    setupFilesAfterEnv: [require.resolve('../../helpers/setupFiles/jasmine')],
    testEnvironment: require.resolve('jest-environment-jsdom-fourteen'),
    testMatch: [`${testMatchPrefix}**/?*.(${testMatchTypes.join('|')}).(j|t)s?(x)`,
    ],
    testPathIgnorePatterns: ['/node_modules/', '/fixtures/'],
    transform: {'^.+\\.(js|jsx|ts|tsx)$': require.resolve('../../helpers/transformers/javascript',),
      '^.+\\.(css|less|sass|scss|stylus)$': require.resolve('../../helpers/transformers/css',),
      '^(?!.*\\.(js|jsx|ts|tsx|css|less|sass|scss|stylus|json)$)': require.resolve('../../helpers/transformers/file',),
    },
    verbose: true,
    transformIgnorePatterns: [// 加 [^/]*? 是为了兼容 tnpm 的目录构造
      // 比方:_umi-test@1.5.5@umi-test
      // `node_modules/(?!([^/]*?umi|[^/]*?umi-test)/)`,
    ],
    // 用于设置 jest worker 启动的个数
    ...(process.env.MAX_WORKERS
      ? {maxWorkers: Number(process.env.MAX_WORKERS) }
      : {}),
  }
  • 合并配置局部代码如下:
const config = mergeConfig(createDefaultConfig(cwd, args),
  packageJestConfig,
  userJestConfig
);

其源码在此:点击跳转

技术栈抉择

因为 umi 内置的 jest 配置是不能满足咱们我的项目的需要的,jest 是 JavaScript 的测试框架,如果须要对 dom 做单元测试,须要引入更多测试库

Jest

jest 是 umi 自带的,这个是根底,须要对其有根本的意识,其文档如下:
https://jestjs.io/zh-Hans/

ts-jest

ts-jest 是让咱们能用 Typescript 写测试代码的转换工具,也是 umi 内置配置,很少须要更改,如需更改可参考官网文档:
https://kulshekhar.github.io/ts-jest/docs/

React Testing Library

React Testing Library 是 测试 React 组件的解决方案,其蕴含了 React 官网的测试工具 react-dom/test-utils 的 API,也是 React 官网举荐的测试 DOM 库。
至于为什么不必老牌测试库 Enzyme , 能够看作者的 blog 这篇文章:
https://kentcdodds.com/blog/introducing-the-react-testing-library

平时写测试代码时更多接触的是 React Testing Library , 其文档如下:
https://testing-library.com/docs/react-testing-library/intro
除了 @testing-library/react 外,平时 @testing-library 旗下的其余库,例如 @testing-library/user-event 用来模仿交互的。@testing-library/react 是基于 @testing-library/dom 的,所以对 @testing-library/dom 有根本的理解,有助于深刻了解 @testing-library/react

Mock Service Worker

Mock Service Worker (MSW) 是用来 mock Axios 的申请后果的,执行 REST/GraphQL API
其文档如下:https://github.com/mswjs/msw

应用疏导

单元测试编写

这里不做过多介绍,能够参考官网 example 及其他领导文章,以及现有的单元测试代码,分享一下如下几篇

  1. 官网 demo:https://testing-library.com/docs/react-testing-library/example-intro
  2. 作者 blog—Common mistakes with React Testing Library — https://kentcdodds.com/blog/common-mistakes-with-react-testing-library
  3. 测试 react-toolkit — https://ogzhanolguncu.com/blog/testing-react-redux-toolkit-with-typescript

注:写单元测试可能加深你对代码的了解以及对本人代码的信任度

运行

单元测试环境曾经搭建好了,只须要执行对应的命名就能够了

"test": "umi test --no-cache", // 一次性执行单元测试
"test:watch": "umi test --watch", // 实时监听代码变动,执行
"test:clear": "umi test --clearCache",
"test:coverage": "umi test --coverage", // 执行,输入笼罩报告 

配置

有些状况现有的配置不能满足本人的需要,能够依据状况更改配置

  1. jest.config.js
  2. ./src/setupTests.ts

覆盖率

应用了 Istanbul 代码笼罩工具,对于笼罩指标参考:
阮一峰这篇文章 — http://www.ruanyifeng.com/blog/2015/06/istanbul.html
目前我的项目确定如下的笼罩指标:

global: {
  branches: 90,
  functions: 90,
  lines: 90,
  statements: 90,
},

应用 yarn test:coverage 能够测试输入覆盖率报告

踩坑过程问题记录

记录一些问题:以防反复踩坑

  1. Jest test fails : TypeError: window.matchMedia is not a function
  2. Jest + react-testing-library: Warning update was not wrapped in act()
  3. Uncaught [Error: Invalid hook call. Hooks can only be called inside of the body of a function component — mock module 在 setupTests.ts 中引入
  4. The module factory of jest.mock() is not allowed to reference any out-of-scope variable — 用 require 在外面解决, 参考:https://github.com/facebook/jest/issues/2567

后续打算

  1. 抽离公共测试代码,使写单测更加丝滑
  2. 补充单元测试,满足覆盖率指标
  3. 端对端测试搞起来
  4. 接入到 CI/CD 中
正文完
 0