如何在Jest中重置或清除间谍?

191

我有一个间谍在测试套件中的多个测试中被用于多个断言。

我该如何清除或重置该间谍,以便在每个测试中拦截的方法都被视为未被调用?

例如,如何使 'does not run method' 的断言成立?

const methods = {
  run: () => {}
}

const spy = jest.spyOn(methods, 'run')

describe('spy', () => {
  it('runs method', () => {
    methods.run()
    expect(spy).toHaveBeenCalled() //=> true
  })

  it('does not run method', () => {
    // how to make this true?
    expect(spy).not.toHaveBeenCalled() //=> false
  })
})
5个回答

254

感谢@sdgluck的回答,尽管我想补充一下我的情况,因为我有多个测试都使用了同一个 spy,所以我希望每次测试后都有一个清晰的状态。因此,我没有在之前的测试中调用mockClear(),而是将其移到了afterEach()中(或者您可以与beforeEach一起使用),像这样:

afterEach(() => {    
  jest.clearAllMocks();
});

最后,我的测试像应该的那样工作,而不需要从以前的测试中调用间谍。您也可以阅读它们的文档

选项2

如果您希望从全局级别执行此操作,还可以更新您的jest.config.js(或来自package.json

module.exports = {
  clearMocks: true,
  // ...
}

你可以阅读 Jest 文档 了解更多。


73
如果你想将模拟函数恢复为其原始实现,可以使用jest.restoreAllMocks(); - ZorleQ
17
你可以在Jest配置中添加restoreMocks: true来自动调用restoreAllMocks(),以便在每个测试后恢复所有mocks。个人而言,我从来没有让mocks在任何两个测试之间保持不变的理由,因此我喜欢在每个测试之间盲目地重置它们,而无需在afterEach()块中编写它们作为清理项。 - user2490003
1
你也可以在同一个测试套件中的两个断言之间调用 jest.clearAllMocks();。这对于将所有针对单个方法的测试分组到一个测试套件下,但希望断言不记住其先前值的情况非常有用。 - Nadav
1
你可以简单地使用 afterEach(jest.clearAllMocks) - trevorgk

78

Jest间谍与模拟函数具有相同的API。模拟函数的文档在这里,其中指定了一个方法mockClear,它:

重置存储在mockFn.mock.callsmockFn.mock.instances数组中的所有信息。

通常,当你想要在两个断言之间清除模拟使用数据时,这非常有用。

(强调是我自己加的)

因此,我们可以使用mockClear来“重置”间谍。使用您的示例:

const methods = {
  run: () => {}
}

const spy = jest.spyOn(methods, 'run')

describe('spy', () => {
  it('runs method', () => {
    methods.run()
    expect(spy).toHaveBeenCalled() //=> true
    /* clean up the spy so future assertions
       are unaffected by invocations of the method
       in this test */
    spy.mockClear()
  })

  it('does not run method', () => {
    expect(spy).not.toHaveBeenCalled() //=> true
  })
})

这里是在CodeSandbox中的示例


5
可能需要更新此内容。截至今天,使用Jasmine ~2.8.6和jest 24.0.9,这是不正确的。 "属性'mockClear'在类型'Spy'上不存在。" - Bardicer
@Bardicer 这种方法在最新的Jest中仍然有效,并且根据Jest文档是正确的。请参阅我在答案末尾放置的链接,其中演示了它在CodeSandbox中的工作情况。 - sdgluck
2
...那好吧...我想我只是在jest开始流行的那一天尝试让它工作。这不会是第一次库决定变得困难并且不能按预期工作。 - Bardicer
嗯...我看到了@Bardicer看到的东西。版本“2.99.0”。你确定你没有安装jest-mock-extended或类似的东西吗?"_jest-mock-extended暴露了mockClear和mockReset用于重置或清除mocks..." - ruffin

30

如果您想恢复先前添加到间谍中的方法的原始行为,可以使用mockRestore方法。

请查看下面的示例:

class MyClass {
    get myBooleanMethod(): boolean {
        return true;
    }
}

const myObject = new MyClass();
const mockMyBooleanMethod = jest.spyOn(myObject, 'myBooleanMethod', 'get');
// mock myBooleanMethod to return false
mockMyBooleanMethod.mockReturnValue(false);
// restore myBooleanMethod to its original behavior
mockMyBooleanMethod.mockRestore();

谢谢@Daniel,这个是唯一在我的情况下有效的解决方案,其中破损的测试正在执行spy = jest.spyOn(document),需要执行两次,第二次会导致“TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.”。 - Carlos Jaime C. De Leon
我也是,浪费了几个小时后,这是唯一有效的解决方案。 - Aishwat Singh
一样,浪费了几个小时后,这是唯一有效的解决方案。 - undefined

16

在 @ghiscoding 的回答的基础上,您可以在 Jest 配置中指定 clearMocks,这相当于在每个测试之间调用 jest.clearAllMocks()

{
...
    clearMocks: true,
...
}

查看文档这里


1
在jest.config.js中添加mockReset,而不是clearMocks,因为这样不会在测试之间删除任何模拟实现(即mockReset是更加谨慎的选项,并将在测试之间删除实现 - 在我看来,这是正确的做法,因为每个测试应该是隔离的)。
{
...
    mockReset: true,
...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接