Jest Mock
mock 异步方法
1 2 3 | export const runCallback = callBack => { return callBack(); }; |
我们对上面的代码进行测试:
1 2 3 4 5 6 7 | import { runCallback } from "./demo" ; test( "测试 runCallback" , () => { const fn = jest.fn(); // mock函数,捕获函数的调用 runCallback(fn); expect(fn).toBeCalled(); // expect(runCallback(() => "hello")).toBe("hello"); }); |
通过 jest.fn
生成的 mock 函数,我们可以打印其 fn.mock
,得到以下结果:
calls
被调用的情况,通过 fn.mock.calls.length
可获取 mock 函数被调用次数,每个数组里存放传递给 mock 函数的参数instances
jest.fn
生成函数的 this 指向invocationCallOrder
传递进去函数的执行顺序results
函数输出的结果
1 2 3 4 5 6 7 8 9 10 | // mock函数返回123,results的value变为123 const fn = jest.fn(() => 123); // 等价于 fn.mockReturnValue( "123" ); // 等价于 fn.mockImplementation(() => 123); // 模拟返回一次函数结果 fn.mockReturnValueOnce( "123" ); // 等价于 fn.mockImplementationOnce(() => 123); |
测试异步代码每次都发送真实请求,无疑是很慢的,我们可以使用 mock 模拟请求方法
1 2 3 4 5 | // demo.js import axios from "axios" ; export function getData() { return axios.get( "http://www.dell-lee.com/react/api/demo.json" ); } |
- 同级目录下建一个 **mocks** 的文件夹,建立同名的文件,此文件就是模拟请求的文件
1 2 3 4 5 | export function fetchData() { return Promise.resolve({ success: true }); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 模拟 request 模块 jest.mock( "./request.js" ); // 也可以在 jest.config.js 里面手动设置 automock 为 true // 取消 mock // jest.unmock("./demo.js"); import { fetchData } from "./request" ; test( "测试 fetchData" , () => { // 此请求实际会请求 __mocks__ 下的 request.js 方法 return fetchData().then(data => { expect(data).toEqual({ success: true }); }); }); |
如果我们 request.js
某些方法不需要 mock
1 | const { getNumber } = jest.requireActual( "./request.js" ); |
Mock Timers
当我们有如下代码需要测试的时候:
1 2 3 4 5 | export default callback => { setTimeout(() => { callback(); }, 3000); }; |
测试:
1 2 3 4 5 6 7 | import timer from "./timer" ; test( "测试 timer" , done => { timer(() => { expect(1).toBe(1); done(); }); }); |
我们不可能总是等待定时器完才去执行用例,这时候我们要用 Jest 来操作时间!步骤如下:
- 通过 jest.useFakeTimers() 使用 jest "自制的" 定时器
- 执行 timer 函数之后,快进时间 3 秒 jest.advanceTimersByTime(3000),这个方法可以调用任意次,快进的时间会叠加
- 这时候我们已经穿梭到了 3 秒后,expect 也能生效了!
1 2 3 4 5 6 7 8 9 10 11 | import timer from "./timer" ; beforeEach(() => { jest.useFakeTimers(); }); test( "测试 timer" , () => { // jest.fn() 生成的是一个函数,这个函数能被监听调用过几次 const fn = jest.fn(); timer(fn); jest.advanceTimersByTime(3000); expect(fn).toHaveBeenCalledTimes(1); }); |
Mock 类
- 当我们只关注类的方法是否被调用,而不关心方法调用产生的结果时,可以 mock 类
在 util.js
中定义了 Util
类
1 2 3 4 | export class Util { a() {} b() {} } |
在 useUtil.js
调用这个类
1 2 3 4 5 6 | import { Util } from "./util" ; export function useUtil() { let u = new Util(); u.a(); u.b(); } |
我们需要测试 u.a
和 u.b
被调用
jest.mock("util.js")
会将 Util、Util.a、Util.b 都 mock 成 jest.fn
1 2 3 4 5 6 7 8 9 | jest.mock( "util.js" ); // mock Util 类 import { Util } from "./util/util" ; import { useUtil } from "./util/uesUtil" ; test( "util 的实例方法被执行了" , () => { useUtil(); expect(Util).toHaveBeenCalled(); expect(Util.mock.instances[0].a).toHaveBeenCalled(); expect(Util.mock.instances[0].b).toHaveBeenCalled(); }); |
Snapshot 快照测试
- 将文件内容拍照一样拍下来。下次运行测试用例的时候,如果内容变化,则会报错
config.js
1 2 3 4 5 6 7 | export const generateConfig = () => { return { server: "https://localhost" , port: 8080, domain: "localhost" }; }; |
测试用例部分:
1 2 3 4 5 | import { generateConfig } from "./config" ; test( "测试 generateConfig" , () => { // 保存会生成 __snapshots__ 目录,记住配置相关内容 expect(generateConfig()).toMatchSnapshot(); }); |
改变 config 文件内容,测试不通过,按 u
可以更新快照
如果有两个快照改变,我们需要一个个更新,我们可以按 i
进入以下界面:
按 s
先跳过此次测试用例
按 u
可一个个更新快照内容,使得测试通过
如果我们配置有不断变化的量:
我们可以这样测试,保证 time 是一个 Date
类型即可
1 2 3 4 5 | test( "测试 generateConfig" , () => { expect(generateConfig()).toMatchSnapshot({ time: expect.any(Date) }); }); |
我们除了可以成目录保存快照内容,还可以生成行内快照,存放本文件即可
1 2 3 4 | test( "测试 generateConfig" , () => { // 需要安装prettier expect(generateConfig()).toMatchInlineSnapshot(); }); |
DOM 测试
- jest 自己模拟了一套
jsDom api
,所以我们能使用 jest 测试 dom
dom.js
1 2 3 4 | export function addDivToBody() { const div = document.createElement( "div" ); document.body.appendChild(div); } |
测试:
1 2 3 4 5 6 | import { addDivToBody } from "./timer" ; test( "测试 addDivToBody" , () => { addDivToBody(); addDivToBody(); expect(document.body.querySelectorAll( "div" ).length).toBe(2); }); |
现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
qq群号:485187702【暗号:csdn11】
最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走! 希望能帮助到你!【100%无套路免费领取】