Jest.spyOn在同describe多测试用例中上下文共享问题
问题原因及解决方案
问题出在你用jest.spyOn(Group.prototype, 'xxx')创建的间谍函数挂载在共享的原型对象上,所有测试用例会共用这个间谍。第一个测试执行时触发的方法调用记录会被保留,第二个测试运行时,这些旧的调用记录会被新创建的间谍继续统计,导致断言失败。
解决方法有两种:
1. 每个测试结束后手动恢复原型方法
在每个测试用例中,创建间谍后通过mockRestore()方法恢复原方法,彻底清除间谍的影响:
it('should update only perm and name', async () => { const spyOnPerm = jest.spyOn(Group.prototype, 'changePermissions'); const spyOnName = jest.spyOn(Group.prototype, 'changeName'); const spyOnIsDpt = jest.spyOn(Group.prototype, 'changeIsDepartment'); try { const command = new ChangeGroupPermissionCommand({ group, propsToChange: { permissions: [Permission.createFromBitmap('@iam.11111111')], name: 'new name' + Math.random(), }, }); await context.run(author, async () => { await handler.execute(command); expect(spyOnPerm).toBeCalledTimes(1); expect(spyOnName).toBeCalledTimes(1); expect(spyOnIsDpt).not.toBeCalled(); }); } finally { // 恢复原型上的原方法,清除间谍 spyOnPerm.mockRestore(); spyOnName.mockRestore(); spyOnIsDpt.mockRestore(); } }); it('should update only department status', async () => { const spyOnPermission = jest.spyOn(Group.prototype, 'changePermissions'); const spyOnName = jest.spyOn(Group.prototype, 'changeName'); const spyOnIsDpt = jest.spyOn(Group.prototype, 'changeIsDepartment'); try { const command = new ChangeGroupPermissionCommand({ group, propsToChange: { isDepartment: true, }, }); await context.run(author, async () => { await handler.execute(command); expect(spyOnPermission).not.toBeCalled(); expect(spyOnName).not.toBeCalled(); expect(spyOnIsDpt).toBeCalled(); }); } finally { spyOnPermission.mockRestore(); spyOnName.mockRestore(); spyOnIsDpt.mockRestore(); } });
2. 全局统一清理间谍
在测试文件顶部添加afterEach钩子,自动处理所有间谍的清理工作:
// 全局钩子:每个测试结束后恢复所有间谍的原方法 afterEach(() => { jest.restoreAllMocks(); }); // 若只需重置调用计数(无需恢复原方法),可改用: // afterEach(() => { // jest.clearAllMocks(); // }); it('should update only perm and name', async () => { // 原测试代码保持不变 }); it('should update only department status', async () => { // 原测试代码保持不变 });
注意:jest.restoreAllMocks()会恢复所有通过jest.spyOn创建的间谍的原方法,适合需要确保原方法行为不受前序测试影响的场景;jest.clearAllMocks()仅清除调用次数和参数记录,不会恢复原方法,适合仅关注调用计数的场景。
内容的提问来源于stack exchange,提问作者Paulo Santana
相关产品推荐
相关产品推荐

