Ken*_*win 5 javascript unit-testing node.js async-await jestjs
我无法让 Jest mockImplementation 在特定上下文中使用 Promise.resolve() 返回数据。
在我的 Node.js 代码中,我有一个结构,将所有 API 调用代码放在一个类 (Api) 中,将所有业务逻辑放在另一个类 (Repo) 中。当您实例化 Repo 时,它会为自己创建 Api 类的实例:this.api = new Api()
我正在尝试在 Repo 级别测试一个函数,并模拟 Api 调用,这样我们在测试期间实际上不会进行任何查询。
const data = { postId: 3, id: 3, name: 'Bob Your Uncle' };
beforeEach(() => {
getSpy = jest.spyOn(repo.api, 'getPage').mockImplementation(() => {
Promise.resolve(data);
});
});
Run Code Online (Sandbox Code Playgroud)
当我执行该函数时,expect(getSpy).toHaveBeenCalledTimes(1)返回 true,但它返回的值是“未定义”而不是预期的承诺已解决。
当我在现实生活中运行代码时,它工作得很好,但测试失败了。我怀疑问题可能与我正在测试的代码正在调用第二个用户编写的类有关,但我不确定。我发现这个问题Jest: Spy on object method? 这似乎是相关的,但他们的解决方案(将 .prototype 添加到间谍On参数)并没有帮助我——他们正在使用本机JS对象而不是用户定义的对象,这似乎足以解释差异。
这是完整的describe块:
describe('Repo: fetchRand', () => {
const data = { postId: 3, id: 3, name: 'Bob Your Uncle' };
beforeEach(() => {
getSpy = jest.spyOn(repo.api, 'getPage').mockImplementation(() => {
Promise.resolve(data);
});
});
afterEach(() => {
jest.clearAllMocks();
});
it('should fetch call this.api.getPage once', async () => {
let res = await repo.fetchRand();
expect(getSpy).toHaveBeenCalledTimes(1);
});
it('should return an object with a postId and an name', async () => {
let res = await repo.fetchRand();
expect(res).toHaveProperty('postId');
expect(res).toHaveProperty('name');
});
});
Run Code Online (Sandbox Code Playgroud)
和正在测试的模块:
const Api = require('./Api');
module.exports = class Repository {
constructor() {
this.api = new Api();
}
async fetchRand() {
let id = this.getRandomInt(5);
let res = await this.api.getPage(id);
return res;
}
getRandomInt(max) {
return Math.floor(Math.random() * max) + 1;
}
};
Run Code Online (Sandbox Code Playgroud)
以及包含完整代码的 GitHub 存储库的链接- 运行npm test -- Repo.test.js以复制问题。(这不是我真正的项目,只是复制问题基本性质的最简单的完整代码。)
该问题特定于 JavaScript 箭头语法,而不是 Jest。getPage间谍 不返回承诺,因此它返回undefined。
它应该是使用不带括号的隐式返回:
.mockImplementation(() => (
Promise.resolve(data);
));
Run Code Online (Sandbox Code Playgroud)
或者显式返回:
.mockImplementation(() => {
return Promise.resolve(data);
});
Run Code Online (Sandbox Code Playgroud)
返回承诺的间谍实现的快捷方式是:
.mockResolvedValue(data);
Run Code Online (Sandbox Code Playgroud)
Estus Flask 的评论引导我写下了答案。与类中类的业务完全无关,我猜只是使用了错误的模拟。
这一改变奏效了:
getSpy = jest.spyOn(repo.api, 'getPage').mockResolvedValue(data);
Run Code Online (Sandbox Code Playgroud)