期望被测函数内部的模拟解析值

发布时间:2020-07-07 15:45

请记住,我对Jest还是很陌生,并且对Node Promise的内部知识并不熟悉。我知道async函数实际上是返回Promise的函数,我的想法取得了很好的成功。

我有一个要测试的功能。它具有在执行任何其他工作之前先导入的依赖项。根据传递给foo的输入,该依赖项可能会返回不同的内容,这可能会或可能不会影响foo的结果。像这样:

// foo.js

const someOtherWork = require("../bar/baz");

module.exports = async function foo() {
  const array = await someOtherWork();
  ... do other things ...
  return someStuff;
}

我导入了一个函数来帮助foo试图完成的工作。

在测试中,我像这样监视someOtherWork函数:

// foo.test.js

const someOtherWork = jest.requireActual("../bar/baz");
const mockSomeOtherWork = jest.fn().mockImplementation(someOtherWork);
jest.mock("../bar/baz", () => mockSomeOtherWork);

const foo = require("./foo.js");

// ...tests...

有了这个,我可以断言mockSomeOtherWork是用特定参数调用的,甚至可以返回正确的输出。我绊倒的地方是当我的模拟依赖项(在这种情况下为someOtherWork)返回Promise时。

当我尝试断言Promise使用特定值解析而未在测试代码中调用模拟函数时,它始终通过测试:

expect(mockSomeOtherWork).toHaveReturnedWith(Promise.resolve([my, array, of, expected, values])); // succeeds correctly
expect(mockSomeOtherWork).toHaveReturnedWith(Promise.reject("lol nope"); // succeeds ERRONEOUSLY

当我断言它返回Array或其他任何东西时,我已经成功地通过了测试,

expect(mockSomeOtherWork).toHaveReturnedWith(Array); // fails correctly
expect(mockSomeOtherWork).toHaveReturnedWith([my, array, of, expected, values]); // fails correctly

但是Promise的任何一种通过了测试,这意味着我不能从断言中承担任何责任!

对于Jest,我开始弄清楚Promise是一个最不透明的对象,我必须await或附加回调(通过then或{{1 }})找出其中的内容。诺言是否不记得它们已经解析的值供我以后检查,而无需重新调用返回它的函数?我不想依赖于断言catch的其他依赖关系或someOtherWork的返回值,因为那些选项假设foo可能随时更改。我已经在foo上有了一个有效的间谍模拟物。我应该从someOtherWorkPromise那里获取返回的mockSomeOtherWork.mock.results[0].value吗?是否有“正确”的方法来断言受测单元的依赖性的await结果?

回答1

这是我的解决方法:

// If all is well, this should be a Promise
const results = mockSomeOtherWork.mock.results[0].value;

// If that Promise resolves to the right stuff, gucci!
const expected = [my, array, of, expected, values];
await expect(results).resolves.toStrictEqual(expected); // passes correctly

// This should fail, because the promise resolved to `expected`
const notExpected = [something, else];
await expect(results).resolves.toStrictEqual(notExpected); // fails correctly

我认为,假设Promise是不透明的,我确实需要await来声明其值。我相信这样做不会带来额外的调用或工作,我可以通过断言expect(mockSomeOtherWork).toHaveBeenCalledTimes(1)来证明这一点。由于此断言在我上面的变通方法之前和之后均在测试中成功,因此必须在foo的正文中进行一次调用。

如果Jest有一组toHaveResolvedWith匹配器,那就太好了,但是对于我今天的目的来说,效果很好。