为什么我必须自己调用promise.then()来测试ES6的承诺?

时间:2017-05-23 10:20:46

标签: reactjs unit-testing asynchronous jestjs es6-promise

这是this one的后续问题(没有必要阅读这个问题来解答这个问题。)

以下面的React组件为例:

// ... Note that the mean subtraction is always carried
// out before scaling.

使用Jest,我们可以断言class Greeting extends React.Component { constructor() { fetch("https://api.domain.com/getName") .then((response) => { return response.text(); }) .then((name) => { this.setState({ name: name }); }) .catch(() => { this.setState({ name: "<unknown>" }); }); } render() { return <h1>Hello, {this.state.name}</h1>; } } 等于name请求返回的某些文字:

getName

但以下情况并不合适:

test("greeting name is 'John Doe'", () => {
    const fetchPromise = Promise.resolve({
        text: () => Promise.resolve("John Doe")
    });

    global.fetch = () => fetchPromise;

    const app = shallow(<Application />);

    return fetchPromise.then((response) => response.text()).then(() => {
        expect(app.state("name")).toEqual("John Doe");
    });
});

我的意思是,我在某种程度上复制了测试文件中的实现。

我必须在测试中直接调用return fetchPromise.then((response) => response.text()).then(() => { expect(app.state("name")).toEqual("John Doe"); }); then(),这感觉不对。特别是当catch()也返回一个承诺时,我有两个链式response.text()只是断言then()等于name

我来自Angular,在那里可以调用John Doe并在之后进行断言。

难道没有类似的方法来实现这一目标吗?或者还有另一种方法吗?

2 个答案:

答案 0 :(得分:2)

在与同事讨论这个问题后,我会回答我自己的问题,这让我的事情变得更加清晰。也许上面的问题已经回答了我的问题,但我会用一些我能更好理解的文字给出答案。

我并没有从原始实现中调用then(),我只是在另外的then()链接后执行

另外,更好的做法是将fetch()调用及其所有then()catch()放入其自己的函数中并返回承诺,如下所示:

requestNameFromApi() {
    return fetch("https://api.domain.com/getName")
        .then((response) => {
            return response.text();
        })
        .then((name) => {
            this.setState({
                name: name
            });
        })
        .catch(() => {
            this.setState({
                name: "<unknown>"
            });
        });
}

测试文件:

test("greeting name is 'John Doe'", () => {
    global.fetch = () => Promise.resolve({
        text: () => Promise.resolve("John Doe")
    });

    const app = shallow(<Application />);

    return app.instance().requestNameFromApi.then(() => {
        expect(app.state("name")).toEqual("John Doe");
    });
});

哪个更有意义。你有一个“请求函数”返回一个promise,你直接通过调用它来测试该函数的输出,并链接另一个then(),最后调用它,以便我们可以安全地断言我们需要的东西。

如果您对在测试中返回promise的替代方法感兴趣,我们可以像这样编写上面的测试:

test("greeting name is 'John Doe'", async () => {
    global.fetch = () => Promise.resolve({
        text: () => Promise.resolve("John Doe")
    });

    await shallow(<Application />).instance().requestNameFromApi();

    expect(app.state("name")).toEqual("John Doe");
});

答案 1 :(得分:1)

我的回答可能很糟糕,但我最近第一次测试了这种功能以及获取承诺。同样的方面使我感到困惑。

我认为你并没有在实现中复制代码,因为你必须推迟你的期望,直到你的mock / test-double承诺的异步部分完成为止。如果你把期望放在那个之外,那么期望将在你设置状态的存根的异步部分之前运行。

基本上你的测试double仍然是测试中的一个promise和expect子句,它依赖于那个执行的double需要在then子句中。