我试图测试一个调用另一个模块函数的函数,该函数返回一个promise, 问题是,jest不会等待完成myFunction并跳出它并将其视为一个承诺,因为结果部分显示了"完成"在"解决"之前打印消息信息。我一直在使用setImmediate,但我宁愿不使用它,也想了解原因。
代码的简化版本如下:
被模拟的模块
// repo.js
const getItems = () => {
console.log('real');
return new Promise((resolve, reject) => {
setTimeout(
() => resolve('result'), 1000);
}
);
}
module.exports = {
getItems
};
被测单位:
// sample.js
const repo = require('./repo');
const myFunction = (req, res) => {
console.log('myFunction');
repo.getItems()
.then(goals => {
console.log('resolve');
res.val = 'OK';
}).catch(err => {
console.log('reject');
res.val = 'Failed';
});
return;
};
module.exports = {myFunction};
测试文件:
// sample.test.js
const repo = require('./repo');
const sample = require('./sample');
const result = {
'message': 'done'
};
describe('Tests for receiving items', () => {
it('should call and be successful. ', () => {
repo.getItems = jest.fn(() => {
console.log('mocking');
return new Promise((resolve) => ( resolve(result) ));
});
const response = {val: 'test'};
const request = {};
sample.myFunction(request, response);
console.log('done');
expect(response.val).toBe('OK');
})
}
);
结果是:
console.log MySample\sample.js:5
myFunction
console.log MySample\sampel.test.js:11
mocking
console.log MySample\sampel.test.js:17
done
console.log MySample\sample.js:9
resolve
Error: expect(received).toBe(expected)
Expected value to be (using ===):
"OK"
Received:
"test"
Expected :OK
Actual :test
答案 0 :(得分:-1)
您编写的测试反映了正确的用法,您可能会说它完成了它的目的,因为它在您的实现中发现了一个错误。
为了表明究竟出了什么问题,我将摆脱一切不需要的东西,这将导致一个更小的例子。 Jest可以运行以下测试文件,它会重现您的问题。
const myFunction = (res) => {
Promise.resolve()
.then(goals => {
res.val = 'OK';
}).catch(err => {
res.val = 'Failed';
});
return;
};
it('should call and be successful. ', () => {
const response = {val: 'test'};
myFunction(response);
expect(response.val).toBe('OK');
})
myFunction
启动一个promise(在此处立即解析,没有任何值)并且不返回任何内容(undefined
)。您还可以使用Promise.reject
代替Promise.resolve
来测试错误部分。当您致电myFunction(response)
时,myFunction
完成时会执行下一行。这不是承诺实际完成的时候,而是功能本身。承诺可能需要花费任何时间,而且无法告诉它何时实际完成。
为了能够知道承诺何时完成,您需要将其返回,因此您可以使用.then()
在承诺解决后执行。 .then()
和.catch()
都会返回一个新的承诺,该承诺会使用返回的值进行解析,在这种情况下,该值又是undefined
。这意味着您需要在.then()
回调中进行断言。类似地,Jest认为测试在退出函数时结束,即使它应该等待承诺得到解决。为此,您可以从测试中返回承诺,Jest将等待其完成。
const myFunction = (res) => {
// Return the promise from the function, so whoever calls myFunction can
// wait for the promise to finish.
return Promise.resolve()
.then(goals => {
res.val = 'OK';
}).catch(err => {
res.val = 'Failed';
});
};
it('should call and be successful. ', () => {
const response = {val: 'test'};
// Return the promise, so Jest waits for its completion.
return myFunction(response).then(() => {
expect(response.val).toBe('OK');
});
})
您也可以使用async
/ await
,但请记住,您仍然需要了解promises的工作方式,因为它使用了下面的promises。 async
函数总是返回一个promise,因此Jest知道等待它的完成。
it('async/await version', async () => {
const response = {val: 'test'};
// Wait for the promise to finish
await myFunction(response);
expect(response.val).toBe('OK');
})
通常你也会从promise(.then()
或.catch()
)返回一个值,而不是改变外部变量(res
)。因为如果你对多个promises使用相同的res
,你将有一个数据竞争,结果取决于首先完成的promises,除非你按顺序运行它们。