• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
小码哥-倩倩
博客园    首页    新随笔    联系   管理    订阅  订阅

(十一)Jest 中的 mock timer

平时开发中我们经常用到定时器setInterval 或者setTimeout ,现在我们就写一个定时器的测试用例代码如下:

// demo.js

export const lazy = (fn)=> {
	setTimeout(() => {
		fn();
	}, 3000);
}

// demo.test.js
import {lazy} from './timerDemo'
test('should call fn after 3s', () => {
const callback = jest.fn();
lazy(callback);
setTimeout(() => {
expect(callback).toBeCalled();
}, 3001);
})

使用npm run test运行测试用例,运行结果如下:

 

 如何解决这个问题呢?

方法一:

之前的笔记有一个done回调函数(五)Jest测试异步代码

此时我们利用done()来解决这个问题,代码如下:

 

import {lazy} from './timerDemo'
test('should call fn after 3s', (done) => {
	const callback = jest.fn();
	lazy(callback);
	setTimeout(() => {
		expect(callback).toBeCalled();
		done();
	}, 3001);
})

 

方法二:

今天我们学习一种新的解决办法,使用mock timer解决这个问题。jest 提供了mock timer 的功能,不要再使用真实的时间在这里等了,一个假的时间模拟一下就可以了。首先是jest.useFakeTimers() 的调用,它就告诉jest 在以后的测试中,可以使用假时间。当然只用它还不行,因为它只是表示可以使用,我们还要告诉jest在哪个地方使用,当jest 在测试的时候,到这个地方,它就自动使用假时间。两个函数,jest.runAllTimers(), 它表示把所有时间都跑完。具体到我们这个测试,我们希望执完lazy(callback) 就调用, 把lazy函数中的3s时间立刻跑完。可以使用jest.runAllTimers();

具体代码如下:

import {lazy} from './timerDemo'
jest.useFakeTimers();//可以使用假函数
test('should call fn after 3s', () => {
	const callback = jest.fn();
	lazy(callback);
	jest.runAllTimers();//让所有定时器立即执行
	expect(callback).toBeCalled();
    //expect(callback).toHaveBeenCalledTimes(1) 也可以使用
})

如果有多个定时器的时候,我们修改demo.js的代码如下:

export const lazy = (fn)=> {
	setTimeout(() => {
		fn();
		console.log('第一个定时器执行')
		setTimeout(()=>{
			console.log('第二个定时器执行')
		},3000)
	}, 3000);
}

此时运行测试用例的时候,两个定时器会立马都被执行掉。但如果我们只想运行最外层的那个定时器时,我们需要引入 runOnlyPendingTimers() ,只执行一个定时操作。具体代码如下: 

//demo.js

export const lazy = (fn)=> {
	setTimeout(() => {
		fn();
		console.log('第一个定时器执行')
		setTimeout(()=>{
			console.log('第二个定时器执行')
		},3000)
	}, 3000);
}

//demo.test.js

import {lazy} from './timerDemo'
jest.useFakeTimers();//可以使用假函数
test('should call fn after 3s', () => {
	const callback = jest.fn();
	lazy(callback);
	jest.runOnlyPendingTimers();//让所有定时器立即执行
	//expect(callback).toBeCalled();
	expect(callback).toHaveBeenCalledTimes(1)
})

自己试着运行一下我们会发现,只有第一个执行了。

同时也可以使用 jest.advanceTimer() 快进几秒。

具体代码使用如下:

//demo.js
export const lazy = (fn)=> {
	setTimeout(() => {
		fn();
		console.log('第一个定时器执行')
		setTimeout(()=>{
			console.log('第二个定时器执行')
		},3000)
	}, 3000);
}

//demo.test.js

import {lazy} from './timerDemo'
jest.useFakeTimers();//可以使用假函数
test('should call fn after 3s', () => {
	const callback = jest.fn();
	lazy(callback);
	jest.advanceTimersByTime(3000)
	expect(callback).toHaveBeenCalledTimes(1)
})

运行结果发现只执行了第一个定时器,如果还想执行第二个,我们可以修改demo.test.js代码如下:

import {lazy} from './timerDemo'
jest.useFakeTimers();//可以使用假函数
test('should call fn after 3s', () => {
	const callback = jest.fn();
	lazy(callback);
	jest.advanceTimersByTime(3000)
	jest.advanceTimersByTime(3000)//第二个的时间以第一个的时间为基数
	//expect(callback).toBeCalled();
	expect(callback).toHaveBeenCalledTimes(1)
})

此时两个定时器都会执行。  使用jest.advanceTimersByTime(n)快进n时间执行定时,多个advanceTimerByTime连用时,后一个会以前一个的时间为基点,如果不想互相影响,我们可以使用钩子函数beforeEach解决这个问题。

 前端交流群:扫码进去

 

 

 

posted @ 2020-05-12 10:18  小码哥-倩倩  阅读(1770)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3