无法测试已解决的承诺的效果

时间:2017-05-23 09:51:02

标签: javascript testing promise mocha sinon

我在用户中有以下代码:

 import { redirectTo } from 'urlUtils';
 export function create(user) {
    api.postUser(user).then((response) => {
      redirectTo(response.userUrl);
    })
 }

我有以下测试:

import * as api from 'api'
import * as user from 'user'

sinon.stub(api, 'postUser').returns(
  Promise.resolve({ userUrl: 'a-url' })
);
sinon.spy(urlUtils, 'redirectTo');
const userData = {id: 2};

user.create(userData);
expect(api.postUser.calledWith(userData)).toBe(true);  // This passes
expect(urlUtils.redirectTo.calledOnce).toBe(true); // This fails

我已经能够在浏览器上测试它,并且重定向正在发生。我在这里错过了什么?我已经存根请求调用同步解析promise,所以这不应该是一个问题。

1 个答案:

答案 0 :(得分:2)

Promise是异步的,所以当你执行expect(urlUtils.redirectTo.calledOnce).toBe(true)时,承诺尚未解决。

解决这个问题的最简单方法是在短暂超时中包含该期望,然后使用您正在使用的测试框架提供的任何实用程序来表示异步测试已完成。像这样:

setTimeout(() => {
  expect(urlUtils.redirectTo.calledOnce).toBe(true);
  done();
}, 5);

另一个更好的解决方案是实际使用存根返回的承诺。首先,请参考该承诺:

替换:

sinon.stub(api, 'postUser').returns(
  Promise.resolve({ userUrl: 'a-url' })
);

使用:

const postUserPromise = Promise.resolve({ userUrl: 'a-url' });
sinon.stub(api, 'postUser').returns(postUserPromise);

然后写下你的期望:

postUserPromise.then(() => {
  expect(urlUtils.redirectTo.calledOnce).toBe(true);
  done();
});

done()是大多数测试框架(据我所知,至少是Jasmine和Mocha)提供的功能,表示异步测试已完成。你将它作为定义测试函数的第一个参数,并在函数签名中指定它,告诉测试框架你的测试是异步的。

示例:

it("is a synchronous test, completed when test function returns", () => {
  expect(true).to.equal(true);
});

it("is an asynchronous test, done() must be called for it to complete", (done) => {
  setTimeout(() => {
    expect(true).to.equal(true);
    done();
  }, 5000);
});