繁体   English   中英

承诺在 Jest 测试中没有正确拒绝

[英]Promise not rejecting correctly in Jest test

当承诺拒绝使用 Jest 时,我正在尝试测试console.error输出。 我发现在我的测试运行后,承诺似乎正在解决,导致测试失败。

示例函数:

export default function doSomething({ getData }) {

  const success = data => {
    //do stuff with the data
  }
  const handleError = () => {
    //handle the error
  }

  getData.then(response => success(response)).catch(error => {
    console.error(error)
    handleError()
  })

}

示例测试文件:

import doSomething from "doSomething"

it("should log console.error if the promise is rejected", async () => {
  const getData = new Promise((resolve, reject) => {
    reject("fail");
  });
  global.console.error = jest.fn();
  await doSomething({ getData });
  expect(global.console.error).toHaveBeenCalledWith("fail");
})
//fails with global.console.error has not been called

当我探索这个问题时,我注意到如果我添加一个 console.log 并等待它,它就可以工作。

这将通过...

import doSomething from "doSomething"

it("should log console.error if the promise is rejected", async () => {
  const getData = new Promise((resolve, reject) => {
    reject("fail");
  });
  global.console.error = jest.fn();
  await doSomething({ getData });
  await console.log("anything here");
  expect(global.console.error).toHaveBeenCalledWith("fail");
})

我如何正确测试? 我应该重构我的getData函数的调用方式吗? 一旦doSomething函数被调用,它就需要被调用。

为什么原始测试失败?

理解为什么第一个测试示例不会通过的技巧是深入研究await运算符实际在做什么。 来自Mozilla 文档

[rv] = await expression;
  • expression - 一个 Promise 或任何要等待的值。
  • rv - 返回 Promise 的已履行值,如果它不是 Promise,则返回值本身。

在您的第一个测试中, expression的值是doSomething函数的返回值。 您不会从此函数返回任何内容,因此返回值将为undefined 这不是一个 Promise,所以await什么都不做,它只会返回undefined并继续前进。 expect语句将失败,因为您实际上还没有等待内部承诺: getData.then(...).catch(...)

要修复测试,而不添加额外的行,请await console.log("anything here"); , 只需从doSomething函数return内部承诺,以便await运算符将实际操作 Promise。

export default function doSomething({ getData }) {
  return getData.then(...).catch(...);
  ...
}

这是测试这个的正确方法吗?

我不认为doSomething函数的编写方式有什么大问题。 这种依赖注入通常使函数更容易测试,而不是试图模拟函数的内部工作。

我只承认,因为您正在注入一个 Promise ( getData ),并在函数内解析它,所以您使doSomething函数异步(这使得测试变得更加复杂)。

如果您解析了 Promise,然后在它解析为的值上调用doSomethinggetData.then(doSomething).catch(handleError) ,您的doSomething函数将是同步的并且更容易测试。 我还要说,以这种方式编写它会使异步发生的事情变得更加冗长,而原始的doSomething({ getData })将其隐藏在doSomething函数体中。

所以没有什么是严格不正确的,但也许需要考虑的一些事情可能会使测试更容易并且代码更冗长。 我希望这有帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM