lsekfe 发表于 2023-5-24 11:05:39

浅谈Jest进行React单元测试

1.单元测试的定义
  测试根据不同的维度有多种分类方式,按照测试阶段主要有单元测试、集成测试和系统测试。单元测试(Unit Tesing)是针对程序的最小单位,对代码进行正确性检验的一种测试手段。在过程化编程中,最小单元是单个程序、函数、过程等;对于面向对象编程,最小单元是对象方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。
  2.单元测试的意义
  提升效率:通过 mock 数据,及早发现问题,而越早发现Bug,造成的浪费就会越小
  结构设计:单元测试可以充当一个设计工具,有助于开发人员去思考代码结构的设计,让代码更加有利于测试。特别是先写测试,迫使我们把程序设计成易于调用和可测试的,即迫使我们解除软件中的耦合。
  3.安装与配置
  下文介绍使用 Jest 对 React 程序进行单元测试,采用React Testing Library 作为测试工具库。
  安装Jest
  yarn add --dev jest
  yarn add --dev jest-environment-jsdom jest-less-loader
  yarn add @testing-library/jest-dom @testing-library/react


  配置Jest
  jest --init
  √ Would you like to use Jest when running "test" script in "package.json"? … yes
  √ Would you like to use Typescript for the configuration file? … no
  √ Choose the test environment that will be used for testing ? jsdom (browser-like)
  √ Do you want Jest to add coverage reports? … yes
  √ Which provider should be used to instrument code for coverage? ? babel
  √ Automatically clear mock calls and instances between every test? … no


  配置 Babel
  yarn add --dev babel-jest @babel/core @babel/preset-env @babel/preset-react

  在项目的根目录下创建?babel.config.js?,通过配置 Babel 使其能够兼容当前的 Node 版本。
  module.exports = {
  presets: [
      ['@babel/preset-env', {targets: {node: 'current'}}],
      '@babel/preset-react'
  ],
  };


  在package.json中配置如下内容:
  "scripts": {
      "test": "jest",
   },
  "resolutions": {
      "jest-environment-jsdom": "27.4.6"
   },


  在jest.config.js中配置如下内容:
  module.exports = {
  setupFilesAfterEnv: ['@testing-library/jest-dom'],
  testEnvironment: 'jsdom',
  clearMocks: true,
  coverageDirectory: "coverage",
  moduleDirectories: [
      "node_modules", "src"
  ],
  moduleNameMapper: {
      '^@/(.*)$': '<rootDir>/src/$1',
      '\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
        '<rootDir>/test/fileMock.js',
      '\\.(css|less)$': '<rootDir>/test/styleMock.js',
  },
  transform: {
      "^.+\\.(js|jsx)$": "babel-jest",
      '\\.(less|css)$': 'jest-less-loader'
  },
  transformIgnorePatterns: [
      '/node_modules/(?!antd|@ant-design|rc-.+?|@babel/runtime).+(js|jsx)$',
  ],
  }


  其中,fileMock.js与styleMock.js文件内容均为:
  module.exports = {}

  matchMedia.mock.js文件内容如下:
  Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: jest.fn().mockImplementation(query => ({
      matches: false,
      media: query,
      onchange: null,
      addListener: jest.fn(), // deprecated
      removeListener: jest.fn(), // deprecated
      addEventListener: jest.fn(),
      removeEventListener: jest.fn(),
      dispatchEvent: jest.fn(),
  })),
  });


  4.常见问题
  (1)Jest encountered an unexpected token
http://www.51testing.com/attachments/2023/05/15326880_202305231341201jxCP.jpg
  解决方案:
   moduleNameMapper: {
      "^@/(.*)$": "<rootDir>/src/$1",
      '\\.(css|less)$': '<rootDir>/tests/styleMock.js',
      'antd/es/locale/zh_CN':'<rootDir>/tests/styleMock.js'
  },


  (2)无法读取 props.history.push
http://www.51testing.com/attachments/2023/05/15326880_202305231341231TC6R.jpg
  解决方案:
   test('test', async () => {
      const mProps = { history: { push: jest.fn() } }   
      await render(
        <AppStore {...mProps} />
      )
      expect(mProps.history.push).toBeCalledWith('/app/shelve')
  })



页: [1]
查看完整版本: 浅谈Jest进行React单元测试