在承诺中测试承诺

时间:2017-05-25 10:20:03

标签: javascript testing promise mocha

我曾经有过以下代码:

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调用。

2 个答案:

答案 0 :(得分:0)

你应该添加一个return语句,否则你不会在任何地方返回promises:

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()时,您将获得一个数组,其中包含所有promises返回的所有值。 所以这个方法在调用时应该是这样的:

fetchNames(names).then((arrayOfResolvedPromises) => {
 // here you will have all your promised resolved and the array holds all the results
});

因此,在测试中,您可以在所有的块中移动您已完成的承诺将被解决。

此外,我强烈建议您使用库作为承诺来测试承诺。 它有很多很好的方法来测试你的承诺。

https://github.com/domenic/chai-as-promised

答案 1 :(得分:0)

您没有正确使用承诺。你的代码没有一个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();
});