Jest测试框架入门之Mock

本文详细介绍了 Jest 中的 jest.fn(), jest.mock(), jest.spyOn() 的用法。jest.fn() 用于创建可配置行为的模拟函数,可以设置返回值、监听调用。jest.mock() 用于模拟整个模块,常用于隔离测试。jest.spyOn() 则是对现有函数的监听,保持原有行为的同时提供调用监听。通过实例代码展示了这三个工具的使用场景和效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说到mock,大家第一个想到的肯定是项目里经常用来模拟接口返回值的 mockjs库 ,Jest里的mock有所不同,下面会举一些例子来分别讲一讲 jest.fn()、jest.mock()、jest.spyOn()。

一、jest.fn()

jest.fn() 用于创建一个函数,我们可以设置该函数的返回值、监听该函数的调用、改变函数的内部实现等等,我们通过 jest.fn() 创建的函数有一个特殊的 .mock 属性,该属性保存了每一次调用情况,例子:

test('test jest.fn', () => {
  // 通过jest.fn创建一个接收两个参数,返回俩参数相加的值的函数
  const myMock = jest.fn((x, y) => x + y);
  // 打印myMock调用次数
  console.log(myMock.mock.calls.length); // 0

  myMock(1, 2);

  console.log(myMock.mock.calls.length); // 1
  // 打印myMock第一次调用的第一个和第二个参数
  console.log(myMock.mock.calls[0][0], myMock.mock.calls[0][1]); // 1 2
  // 打印myMock第一次调用的返回值
  console.log(myMock.mock.results[0].value); // 3

  myMock('a', 'b');

  console.log(myMock.mock.calls.length); // 2
  // 打印myMock第二次调用的第一个和第二个参数
  console.log(myMock.mock.calls[1][0], myMock.mock.calls[1][1]); // a b
  // 打印myMock第二次调用的返回值
  console.log(myMock.mock.results[1].value); // ab
  
  const obj = {
    name: 'add',
    fn: myMock
  }

  obj.fn(3, 4)
  // 打印myMock第三次调用的实例对象的name属性值
  console.log(myMock.mock.instances[2].name); // add
  
  // 强制修改myMock的返回值
  myMock.mockReturnValueOnce(10).mockReturnValueOnce('x').mockReturnValue(true);

  console.log(myMock(undefined, undefined), myMock(undefined, undefined), myMock(undefined, undefined), myMock(undefined, undefined)); // 10 x true true
})

二、jest.mock()

这个 jest.mock() 看官网老是看不明白,后来看了很多外部资料大概搞懂了。下面将假设一个场景并用代码实现一下,假设我们要测试math.ts里的myAdd函数,这个myAdd函数里调用了来自utils.ts文件的一个模块,而这个utils.ts是一个外部依赖文件或者是已经测试完毕的内部文件,这个时候我们就可以使用 jest.mock() 来模拟整个utils.ts文件(此时utils.ts里各个模块的监听就能做到了,也可以修改返回值什么的),以达到简化测试math.ts里myAdd函数的目的

理一下上面的逻辑,我们模拟的应当是一个已经测试通过了的或是无需测试的文件/模块。下面用代码来实现一下:

// utils.ts
// 该文件包含add、sub等工具函数,且已经测试通过
export const add = (num1: number, num2: number) => {
  return num1 + num2
}

export const sub = (num1: number, num2: number) => {
  return num1 - num2
}
// math.ts
// 我们要测试myAdd函数,但是又不想关心add函数的内部实现
import { add } from "./utils";
const myAdd = (a: number, b: number) => {
  return add(a, b);
}
export default myAdd;

这个时候我们要写测试文件mock.test.ts了:

import myAdd from "./math";
import { add } from "./utils";

// jest.mock("./utils.ts");

test("mock整个utils.ts模块", () => {
  console.log(myAdd(1, 2));

  expect(add).toBeCalledTimes(1);
});

注意下,上面是把 jest.mock(“./utils.ts”) 注释掉了的,看看结果:

在这里插入图片描述
可以看到成功打印出了3,但报了一个错,说接收的add函数不是mock或spy函数,无法监听被调用的次数。我们把上面注释掉的那行代码打开, 重新运行,结果如下:

在这里插入图片描述
打印的值变成了undefined,报错也消失了。这是由于mock了utils.ts整个模块后,add函数也变成了一个返回undefined的普通函数,不过我们可以自己设置它的返回值:

import myAdd from "./math";
import { add } from "./utils";

jest.mock("./utils.ts", () => {
  return {
    add: jest.fn(() => 3)
  }
});
test("mock整个utils.ts模块", () => {
  console.log(myAdd(1, 2));

  expect(add).toBeCalledTimes(1);
});

三、jest.spyOn()

jest.spyOn() 我个人理解是把一个普通函数变成一个可监听的函数,并不改变内部实现(若想改变spyOn函数的具体实现,可使用mockImplementation)。这个理解不一定对,直接看例子吧:

import myAdd from "./math";
const utils = require('./utils')

const spy = jest.spyOn(utils, 'add');
test("mock整个utils.ts模块", () => {
  console.log(myAdd(1, 2));

  expect(spy).toBeCalledTimes(1);
});

结果为:

在这里插入图片描述
可以看到,utils模块里的add函数可以被成功执行(打印出了3),也可以被监听(未报错)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值