如何测试 componentDidMount 时调用的组件函数?

How to test a component function being called when componentDidMount?

我有一个 React JS 组件 MyComponent,我想测试以下用例:

It should call updateSomething() when component on mount

我想出了以下代码:

被测系统 (SUT)

export class MyComponent extends React.Component<Props, State> {
    public componentDidMount() {
        console.log("componentDidMount"); // Debug purpose.
        this.fetchSomething()
            .then(() => {
                console.log("fetchSomething"); // Debug purpose.
                this.updateSomething();
            });
    }

    // These are public for simplicity
    public async fetchSomething(): Promise<any> { }
    public updateSomething() {
         console.log("updateSomething"); // Debug purpose.
    }
}

测试

it("should update something, when on mount", () => {
    const props = { ...baseProps };
    sinon.stub(MyComponent.prototype, "fetchSomething").resolves();
    const spy = sinon.spy(MyComponent.prototype, "updateSomething");

    shallow(<MyComponent {...props} />);

    sinon.assert.calledOnce(spy);
});

结果是测试失败 AssertError: expected updateSomething to be called once but was called 0 times 但所有三个 console.log() 都打印出来了。

我的理解是因为我想在挂载时测试事件,我必须在它创建之前 spy/stub 它,因此我必须监视 MyComponent.Prototype。此外,对于 fetchSomething(),我必须对异步调用进行存根处理并使其成为 .resolves() 以使其继续进行。

但我不明白它怎么还能console.log("updateSomething")而不被窥探。

我不知道 sinon,我也不知道 ts,但是对于简单的 jsjest,它会像这样:

fetchSomething() = Promise.resolve();

然后,在您的测试中,您不必模拟它而只需使用:

const spy = jest.spyOn(MyComponent.prototype, 'updateSomething');

查看是否被调用:

expect(spy).toHaveBeenCalled();

根据 中的 comments/answer,断言在 .updateSomething 被调用之前出现。要解决这个问题,我会等待 componentDidMount 生命周期方法。

所以固定程序如下:

// SUT

public async componentDidMount() {
    //...
    return this.fetchSomething()
        .then(() => {
            //...
        });
}

// Test

it("should update something, when on mount", () => {
    const props = { ...baseProps };

    // Disable lifecycle here to enable stub in between.
    const wrapper = shallow(<MyComponent {...props} />, { disableLifecycleMethods: true });

    sinon.stub(wrapper.instance(), "fetchSomething").resolves();
    const stub = sinon.stub(wrapper.instance(), "updateSomething");

    // Actually call component did mount.
    wrapper.instance().componentDidMount().then(() => {
         sinon.assert.calledOnce(stub);
    });
});