zoukankan      html  css  js  c++  java
  • react 单元测试 (jest+enzyme)

      为什么要做单元测试

      作为一个前端工程师,我是很想去谢单元测试的,因为每天的需求很多,还要去编写测试代码,感觉时间都不够用了。

      不过最近开发了一个比较复杂的项目,让我感觉一旦项目大了、复杂了,而且还是多人维护一个应用,编写测试代码,

      还是很有必要的。毕竟这样做完之后,后边的维护会轻松很多。

      单元测试

      测试代码的最小单元,一个函数就是一个单元

      测试工具 

      主要用到的测试工具是 jest 和 enzyme

      jest 、 enzyme 介绍

      jest 是 facebook 发布的一个开源的,基于 jasmine 框架的 javascript 单元测试工具它提供了很多有效的功能,

      包含了内置的测试环境的 DOM API 来操作 Dom、断言库、mock 等功能,并且 jest 是 react 的官网上面推荐

      的工具。

      enzyme 是 Airbnb 开源的 react 测试类库,提供了一套简洁强大的 api ,可以通过 jq 的风格进行 dom 处理,

      还可以引用一些其他的 dom 操作库。

      react 单元测试的搭建

      react 项目是基于 webpack + babel 来进行构建的。

      安装 npm 包

      首先需要添加一些 jest + enzyme 的 npm 包

    yarn add jest enzyme babel-jest regenerator-runtime react-test-renderer
    

      

      enzyme 需要安装对应的 react 的 adapter 版本

    yarn add enzyme-adapter-react-16
    

      

      

      配置文件

      1、package.json

    "scripts": {
        "test": "jest --colors --coverage"
      },   

      添加颜色和现实覆盖率

      .babelrc 文件

      

    "env": { // 单元测试下配置
        "test": {
          "presets": [
            "react",
            "react-optimize",
            [
              "env",
              {
                "modules": "commonjs", // 主要是添加这个
                "debug": true,
                "useBuiltIns": false,
                "targets": {
                  "browsers": "defaults"
                }
              }
            ],
            "stage-0"
          ]
        }
      }
    

      

      因为测试环境的在 babel 中的配置 dev 为 test。

      所以这里需要特殊配置,modules 的形式是 commonjs 

      添加jest配置文件jest.config

    module.exports = {
      roots: ['<rootDir>/__test__/', '<rootDir>/src/'], // 测试的目录
      modulePaths: ['<rootDir>'],
      coveragePathIgnorePatterns: ['/node_modules/', '/tests/setup.js'], //忽略统计覆盖率的文件
      // bail: true,
      // testRegex: '', // 后缀名称
      // testPathIgnorePatterns: 'est', // 忽略路径
      // moduleNameMapper: { // 与测试无关的资源文件同意mock 掉,这样在import 的时候就不会真的引入这些文件
      //   '^import?': '<rootDir>/build/jestImportMock.js',
      //   '\.(css|less|gif|jpg|jpeg|png)$': '<rootDir>/build/jestStyleMock.js',
      // },
    };
    

      

      

      jest 详解

      

      1、简单测试结构

    function sum(a,b){
        return a+b;
    }
    
    it('adds 1 + 2 to equal 3', () => {
      expect(sum(1, 2)).toBe(3);
    });
    

      

      2、异步的测试结构

    async function sum (a,b){
        return a+b;
    }
    
    it('adds 1 + 2 to equal 3',async () => {
      const total = await sum(1,2)
      expect(total).toBe(3);
    });
    

      

      3、Mock Function 结构

    function forEach(items, callback) {
      for (let index = 0; index < items.length; index++) {
        callback(items[index]);
      }
    }
    
    const mockCallback = jest.fn(x => 42 + x);
    forEach([0, 1], mockCallback);
    
    // 可以 mockCallback.mock 访问 mockCallback 状态
    

      

      1、jest.fn 用来创建一个 mock function

      2、mockCallback.mock 可以访问 mock function 的状态

      mock 的属性:

      calls : 调用的参数数组,保存了每次调用的入参

      calls.length : 调用次数

      calls[0][0] : 第一次调用的时候的第一个参数

      results:调用的结果数组

      results[0].value : 第一次调用的返回结果

      

      执行 mock function

    const myMock = jest.fn();
    console.log(myMock());
    // > undefined
    
    myMock
      .mockReturnValueOnce(10)
      .mockReturnValueOnce('x')
      .mockReturnValue(true);
    
    console.log(myMock(), myMock(), myMock(), myMock());
    //10 x true

      1、用 mockRetrunValueOnce(value) 来预先设置函数的返回值

      2、mymock() 返回预先设置的值

       异步请求的数据模拟

    let fetch = {
       get:() =>{}
    } 
    jest.mock(fetch)
    fetch.get.mockResolvedValue({data:{},status:0})
    fetch.get(url,options)
    // {data:{},status:0}
    

      

      

      4、常用全局方法

      describe(message,()=>{})  : 创建块

      it(message,()=>{}) : 测试单元

       

       5、ecpect 常用方法

       expect(value) : 注入测试单元

       expect.extend({}) : 拓展 expect 方法

    expect.extend({
      toBeBetween(received, arg1, arg2) {
        const min = arg1;
        const max = arg2;
        if (received > min && received < max) {
          return {
            message: '',
            pass: true,
          };
        }
        return {
          message: `received is between in ${min} - ${max}`,
          pass: true,
        };
      },
    });
    
    expect(99).toBeBetween(1,100)
    

      

      expect.anything()  : 返回除了 null 和 undefined 意外的任何类型数据

      expect.any(Number/String) : 任意 数字/字符串

        expect.assertions(num) : 确定在块中调用几次异步

      toBe(value) : 等于

      toHaveBeenCalled() : 确定函数调用

      toHaveBeenCalledTime(number) : 确定被调用的次数

      toHaveBeenCalledWith(arg1,arg2) :取保调用的函数的值

      toHaveBeenNthCalledWith(num,arg2) : 确保第几个参数

      toHaveRetruned() :确保有返回值

      toHave[:Nth]RetrunedWith([:num,]arg) : 确保某一个有返回值

      toContain(item) : 数组中是否包含 

        toMatch(regex) :正则表达式

      

      enzyme 

       enzyme 一共有四个大的 api ( shallow 、mount 、render 、selectors )。

       通过这四个 api 可以对 react 组件进行操作。

       我们可以通过类似于 jquery 的操作来进行 test 。

       

      

  • 相关阅读:
    2020总结来了,文末有福利
    CentOS 用户请关注,你期待的 CentOS Linux 9 再也不会来了
    全球最好的10款波尔多葡萄酒,拉菲居然垫底
    eth以太坊合约开发工具集
    html格式的文字去掉html tag转为纯text文字
    如何隐藏X-Powered-By
    aiXcoder3.0呼之欲出,代码补全 AI,带你进入「个性化智能编程时代」
    windows故障群集修改心跳网卡【原创】
    keepalived非争抢机制不生效报错Received lower prio advert, forcing new election
    MySQL主从复制,启动slave时报错1872 Slave failed to initialize relay log info structure from the repository
  • 原文地址:https://www.cnblogs.com/jiebba/p/10144381.html
Copyright © 2011-2022 走看看