jest.spyOn函数,将在返回结果后调用

时间:2019-02-20 06:26:50

标签: jestjs

考虑一下我们有一些方法的类。我们想窥探是否调用方法B,而一旦执行方法A,则将结果返回给调用方,而方法B将异步执行。该类如下所示。

class Parent {
    constructor() {
        this.conf = [{ id:'1', func: Parent.methodA.bind(Parent)}, { id:'2', func: Parent.methodB.bind(Parent)}]
    }
    static methodA() {
        console.log('methodA is called from methodC');
        return 'methodA';
    }
    static methodB() {
        console.log('methodB is called from methodC');
        return 'methodB';
    }
    methodC(conf) {
        conf.forEach((eachConf) => {
            if(eachConf.id === '1') {
                setImmediate(() => {
                    // Just to call method with conf = [{ id:'2', func: this.methodB.bind(this)}]
                    this.methodC(conf.slice(1));
                })
                return eachConf.func();
            }
            return eachConf.func();
        });
    }
}
module.exports = Parent;

在笑话测试文件中,调用methodC并希望确保methodA具有返回值,并且希望确保methodB也被调用。 testSpy.js const Parent = require('./ parent');

it('check methodA and methodB called', async () => {
    const methodA = jest.spyOn(Parent, 'methodA');
    const methodB = jest.spyOn(Parent, 'methodB');
    const instance = new Parent();
    instance.methodC(instance.conf);
    expect(methodA).toHaveBeenCalled();
    //How to spyOn methodB.
    //expect(methodB).toHaveBeenCalled();
});

返回结果后可以运行几种方法。希望确保所有步骤均已执行,并且最好也获得每个步骤的结果。

2 个答案:

答案 0 :(得分:0)

使用setImmediate时,您需要使用jest.useFakeTimers()jest.runAllTimers()来立即调用您放入setImmediate中的每个回调。

it('check methodA and methodB called', async () => {
    jest.useFakeTimers()
    const methodA = jest.spyOn(Parent, 'methodA');
    const methodB = jest.spyOn(Parent, 'methodB');
    Parent.methodC(Parent.conf);
    jest.runAllTimers()
    expect(methodA).toHaveBeenCalled();
    //How to spyOn methodB.
    //expect(methodB).toHaveBeenCalled();
});

答案 1 :(得分:0)

.bind creates a new function,因此func被设置为this.methodA.bind(this)创建的新功能。

运行jest.spyOn(Parent, 'methodA');时,它会用间谍代替methodA,但这对func没有任何影响。

调用func时会调用新函数,而不会调用methodA上的间谍。


如果要使用spy来验证是否调用了methodA,必须确保调用了methodA

在这种情况下,您无需使用thisbind绑定到this.methodA(这会创建一个新函数),而是可以从箭头函数中调用this(因为箭头函数capture the this of the enclosing lexical scope ...在这种情况下,是构造函数中的constructor() { this.conf = [ { id: '1', func: (...args) => this.methodA(...args) }, { id: '2', func: (...args) => this.methodB(...args) } ]; } ):

func

然后,当调用methodA时,它将调用spy,后者将调用it('check methodA and methodB called', async () => { jest.useFakeTimers(); const methodA = jest.spyOn(Parent, 'methodA'); const methodB = jest.spyOn(Parent, 'methodB'); const instance = new Parent(); instance.methodC(instance.conf); jest.runAllTimers(); expect(methodA).toHaveBeenCalledTimes(1); // SUCCESS expect(methodB).toHaveBeenCalledTimes(2); // SUCCESS }); 并且测试将通过。


更新

这是您更新后的代码示例的有效测试:

jest.useFakeTimers

setImmediate用模拟记忆来代替jest.runAllTimers之类的计时器函数,以记住调用它们的内容。然后methodA运行使用计时器函数安排的所有回调。

methodC第一次被调用。

methodB第一次被调用,methodC被调用,并且由于methodC回调而再次调用setImmediate时也被调用。