我曾经有过以下代码:
function makeCall(userInfo) {
api.postUser(userInfo).then(response => {
utils.redirect(response.url);
})
// other logic
return somethingElse;
}
我能够编写一个看起来像这样的测试:
const successPromise = Promise.resolve({ url: 'successUrl' })
beforeEach(function() {
sinon.stub(api.postUser).returns(successPromise);
}
afterEach(function() {
api.postUser.restore();
}
it "calls API properly and redirects" do
makeCall({});
expect(api.postUser).calledWith(userInfo).toBe(true);
successPromise.then(() => {
expect(utils.redirect.calledWith('successUrl')).toBe(true);
done();
}
emd
一切都是绿色的。
现在,在执行 api postUser 调用之前,我必须添加另一个承诺来进行另一个外部调用,所以我的代码如下所示:
function makeCall(names) {
fetchUserData(names).then(userData => {
return api.postUser(userData).then(response => {
utils.redirect(response.url);
})
})
// other logic
return somethingElse;
}
其中 fetchUseData 是许多承诺的链,例如:
function fetchNames(names) {
// some name regions
return Promise.all(names);
}
function fetchUserData(names) {
fetchUsersByNames(names).then(users => {
// For now we just choose first user
{
id: users[0].id,
name: users[0].name,
}
});
}
我的测试失败了。我正在尝试了解如何更改我的测试,以确保我仍在测试我是否正确执行了最终的 API 调用并且重定向也已完成。我想存根fetchUserData(names)
,以防止执行该HTTP调用。
你没有正确使用承诺。你的代码没有一个单一的return
语句,而它应该有几个(或者它应该以你不需要它们的方式使用箭头函数,而你没有这样做(。
修复您的代码:
function makeCall(names) {
// v---- return
return fetchUserData(names).then(userData => {
// v---- return
return api.postUser(userData).then(response => {
utils.redirect(response.url);
})
})
}
function fetchUserData(names) {
// v---- return
return fetchUsersByNames(names).then(users => {
// For now we just choose first user
// v---- return
return {
id: users[0].id,
name: users[0].name,
}
});
}
完成此操作后,您可以让测试等待所有操作完成。
测试代码:
makeCall(['name']).then(() =>
expect(api.postUser).calledWith(userInfo).toBe(true);
expect(utils.redirect.calledWith('successUrl')).toBe(true);
done();
});
你应该添加一个 return 语句,否则你不会无处返回承诺:
function fetchNames(names) {
// some name regions
return Promise.all(names);
}
function fetchUserData(names) {
return fetchUsersByNames(names).then(users => {
// For now we just choose first user
{
id: users[0].id,
name: users[0].name,
}
});
}
因此,当您使用 Promise.all(( 时,作为 promise 的结果,您将拥有一个数组,其中包含所有 promise 返回的所有值。因此,调用此方法时应如下所示:
fetchNames(names).then((arrayOfResolvedPromises) => {
// here you will have all your promised resolved and the array holds all the results
});
因此,在您的测试中,您可以将完成的工作移动到将解决所有承诺的块内。
此外,我强烈建议您使用库作为承诺的 chai-as 来测试承诺。它有很多很好的方法来测试你的承诺。
https://github.com/domenic/chai-as-promised