入手前端单元测试(二) -- 匹配器、Mock、配置文件

本文深入介绍了Jest在前端单元测试中的应用,包括expect的使用,如toBe、toBeCloseTo等匹配器,以及如何处理异步代码中的断言。此外,还详细讲解了Mock函数的运用,如模拟函数调用、配置返回值,并展示了如何通过jest.config.js进行测试配置。最后,文章提供了一些实际示例来帮助读者更好地理解和实践。
摘要由CSDN通过智能技术生成

相关文章

1. expect 的用法及 ”匹配器“
  • expect 用来检查某个值是否符合预期,匹配器则是匹配的方法。
  • expect.not 用来检查某个值是否不匹配结果
  • expect.resolves 用来结构 promise ,从而判断其返回值(注意:这种 expect 需要在 test 中 return expect; 或者使用 async await )
  • expect.rejects 同上用来判断 promise reject 后的结果
  • expect.assertions(number) 用来验证在测试期间调用了一定数量的断言,通常用在测试异步代码中

常用匹配器

test('Test Matcher ', async () => {
  await expect(Promise.resolve('some result'))
      .resolves.toBe('some result'); // .resolves 用来解构判断 promise 的返回值
  expect(2 + 2).not.toBe(5); // .not 检查某个值不匹配结果
  expect(2 + 2).toBe(4); // 数值比较
  expect(2.1 + 2.2).toBeCloseTo(4.3); // 浮点值比较
  expect(20).toBeGreaterThan(10); // 大于
  expect(20).toBeLessThan(30); // 小于
  expect(null).toBeNull(); // 是否为 null
  expect(undefined).toBeUndefined(); // 是否为 undefined
  expect(null).toBeDefined(); // undefined 的相反值 null 也算 defined
  expect([]).toBeTruthy(); // 可以使 if 语句为真的结果
  expect('').toBeFalsy(); // 可以使 if 语句为假的结果
  expect('xxxsss').toMatch(/^[a-z]+$/i); // 匹配字符串符合正则规则
  expect([{a: 1}]).toEqual([{a: 1}]); // 对象数组等引用类型判断相等
  expect(['AAA', 'BBB']).toContain('AAA'); // 判断数组是否包含
  expect(() => {
      throw new Error('test error')
  }).toThrow('test error'); // 判断是否抛出了错误
});

// callback 异步代码,通过参数 done 来控制测试是否完成
test('Test Async Code -- Callback', (done) => {
  function callback(data: string) {
      try {
          expect(data).toBe('peanut butter');
          done(); // 必须使用 done 来控制测试执行完成,否则测试在执行 fetchData 时就会结束
      } catch (error) {
          done(error);
      }
  }

  fetchData(callback);
})

test('Test Async Code -- Async', async () => {
  await expect(fetchData()).resolves.toBe('peanut butter');
  await expect(fetchData()).rejects.toMatch('error');
});

test('Test Async Code -- Promise', async () => {
  // 由于断言在 promise 的 catch 中,不一定会执行到,而如果执行不到则代表测试应该失败,可以通过 expect.assertions 来实现在没有执行指定数量断言后的报错
  expect.assertions(1);
  return fetchData().catch(e => expect(e).toMatch('error'));
});

更多 expect 及 匹配器使用查看

2. Mock 函数

jest 提供了 mock 函数,可以用来帮助捕获函数的调用以及在调用过程中的传参, 允许测试时配置返回值,可以用来做假数据

import axios from 'axios';
import Utils from './utils';

// 模拟 axios 模块请求
jest.mock('axios');
const axiosReq = axios as jest.Mocked<typeof axios>;
const utils = new Utils();

describe('测试 Mock 函数', () => {
    test('捕获函数调用', async () => {
        utils.init(5, 1000);
        /**
         * utils.useCallbackFn 是一个需要传入回调函数的方法
         * 通过 jest.fn 包装 我们来创建一个符合 utils.useCallbackFn 的回调函数,
         * 这个回调函数除了普通函数的功能外,还具有记录回调调用情况的能力
         * */
        const mockFn = jest.fn((num: number) => num * 10);
        utils.useCallbackFn(mockFn as unknown as (() => any));

        /**
         * mockFn.mock
         *  - calls 包含所有对此模拟函数的调用参数数组
         *  - results 包含所有对此模拟函数的返回值数组
         *  - instance 包含所有对此模拟函数的实例对象数组(通过 new 创建的实例)
         * */
        expect(mockFn.mock.calls.length).toBe(2); // 检查回到调用几次
        expect(mockFn.mock.calls[0][0]).toBe(5); // 检查第一次调用的参数
        expect(mockFn.mock.results[0].value).toBe(50); // 检查第一次调用时的返回值

        const MockClass = jest.fn();
        const a = new MockClass();
        expect(MockClass.mock.instances[0]).toBe(a); // 检查通过 mockClass 创建的第一个实例

        /**
         * 除了上述通过 mockFn.mock 还可以直接使用 matchers 匹配器来进行验证
         * */

        expect(mockFn).toHaveBeenCalledTimes(2); // 调用几次
        expect(mockFn).toHaveNthReturnedWith(1, 50); // 第一次调用返回值

        // 模拟返回数据
        const mockFn2 = jest.fn();
        mockFn2.mockReturnValue(90);
        expect(mockFn2()).toBe(90);

        // 模拟 axios 模块 请求后返回的数据
        axiosReq.get.mockResolvedValue({data: [90, 200]});
        // utils.getData 中使用了 axios 请求数据
        await expect(utils.getData()).resolves.toEqual({data: [90, 200]})
    })
})

查看 其他 mock 函数相关 API

3. jest 配置文件

配置文件

  • 执行 jest --init ,回答几个问题后就会生成 jest.config.(js|ts) 配置文件
  • 除此之外也可以将配置加载 package.json 的 jest 字段上
  • jest.config.(js|ts) 文件中可以 export 一个配置对象,或者是一个 async function
// jest.config.ts
export default {
  // 在 n 次错误之后停止进行剩下的 test 文件
  bail: 1,
  // 是否在测试时收集覆盖率数据,开启后会降低测试速度
  collectCoverage: true,
  // 覆盖率报告的存放地址
  coverageDirectory: "coverage",
  // 定义收集测试覆盖率的文件来源
  collectCoverageFrom: ['src/components/**', '!**/node_modules/**', '!src/**/*.d.ts'],
  // 列举 jest 收集测试文件的目录,默认是 <rootDir> 也就是配置文件所在的目录
  roots: [
    "<rootDir>/src/components" // 例:只收集 /src/components 下的测试文件
  ],
  // 那些文件会被当做测试文件,默认是 __tests__ 下的 js 以及 命名为 xxx.test.js 的文件 
  testMatch: [ "**/__tests__/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[jt]s?(x)" ]
  // setupFiles 或者 setupFilesAfterEnv 会在每一个 test 文件执行前执行,且 setupFiles 会优先执行们通常用来设置一些环境
  setupFiles: ['react-app-polyfill/jsdom'],
  // 如果是个本地文件可以 通过 <rootDir> 来定义文件路径
  setupFilesAfterEnv: ['<rootDir>/tests/setupTests.ts'],
  // 测试环境 jsdom | node
  testEnvironment: "jsdom",
  // 类似 webpack alias 设置别名,如下设置后就可以直接引用 tests/xxx 
  moduleNameMapper: {
    '^tests/(.*)$': '<rootDir>/tests/$1',
    "\\.(css|less)$": "identity-obj-proxy" // 配置处理样式文件,如果需要自定义可以放在 transform 中实现
  },
  /**
    用来配置 jest 如何处理文件资源
    如下 fileTransformer.js 需要是一个具有如下结构的模块
    module.exports = {
        process(src, filename, config, options) {
            return 'module.exports = ...;';
        },
    };
  */ 
  "transform": {
    "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/fileTransformer.js"
  }
}

更多配置查看 或者查看

参考:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值