繁体   English   中英

在Mocha,Chai和Sinon承诺完成后测试非承诺

[英]Testing non-promises after promise completes with Mocha, Chai and Sinon

我已经在Redux中创建了一个小型学习项目,并且基本上已经从文档中复制了用于异步操作的中间件。 现在,我想为此编写一些测试,以确保在我进行一些更改后它可以正常工作。

为了编写测试,我使用的是Mocha,以及chai,chai-promise和sinon。

无论如何,我对redux都没有问题,但是我不确定如何测试。

来自中间件的相关代码:

export default function callApiMiddleware({ dispatch }) {
  return next => action => {
    // ... various checks

    const [ requestType, successType, errorType ] = types;
    dispatch({ ...payload, type: requestType });

    return callApi().then(
      response => dispatch({ ...payload, type: successType, response }),
      error => dispatch({ ...payload, type: errorType, error })
    );
  }
}

无论承诺是否实现,中间件都会分派适当的操作。

为了测试这一点,我与其他人一起取消了调度功能,并且我还传递了一个虚假的承诺,即根据我要测试的内容来实现或拒绝。

我编写的测试如下所示:

it('should trigger success action when successful', () => {
  let promise = callApiMiddleware({ dispatch, getState })(next)({
    ...action,
    callApi: () => new Promise((resolve, reject) => resolve('SUCCESS'))
  });
  return expect(promise).to.eventually.be.fulfilled;
});

这可以正常工作,但是我遇到的第一个问题是当我尝试模拟可能由于没有互联网连接而导致的被拒绝的承诺时,所以我编写了以下测试:

it('should trigger failure action when failure occurs', () => {
  let promise = callApiMiddleware({ dispatch, getState })(next)({
    ...action,
    callApi: () => new Promise((resolve, reject) => reject('ERROR'))
  });
  return expect(promise).to.eventually.be.rejected;
});

但这失败,并显示以下消息:

AssertionError:预期的诺言被拒绝,但未定义实现

预期的:[未定义]

实际的:[未定义]

这对我来说毫无意义,因为我明确地传递了一个承诺,那就是唯一的功能将被拒绝。

我的另一个问题是,我还想提出其他断言,这些断言与诺言本身没有任何关系,但是必须在诺言完成时进行评估,例如,我想断言dispatch方法被调用了两次。 在测试中,使用sinon对dispatch方法本身进行了测试,以执行所需的断言。 潜在地,我想以此方式做出多个断言。

我尝试了以下方法:

it('should trigger success action when successful', () => {
  let promise = callApiMiddleware({ dispatch, getState })(next)({
    ...action,
    callApi: () => new Promise((resolve, reject) => resolve('SUCCESS'))
  });
  return Q.all([
    expect(promise).to.eventually.be.fulfilled,
    expect(dispatch).to.eventually.be.calledTwice
  ]);
});

但是,这返回了一个非常大的错误,该错误告诉我dispatchthenable即不是承诺。

我对如何执行此操作没有任何想法,因此,我们将不胜感激。

诺言不会抛出错误,因此,如果您在第一个捕获处理程序中捕获到错误,除非再次抛出捕获的错误,否则在下一个处理程序中将实现诺言。

// this does not work
promise.catch((e) => console.log(e)).catch((e) => console.log(e));

如果您希望这样做,则必须重新抛出一个错误。

promise.catch((e) => {
   console.log(e);
   throw e;
}).catch((e) => console.log(e));

如果您希望测试通过,则需要重新抛出在promise的catch处理程序中捕获的错误。 因此,您的代码应如下所示:

export default function callApiMiddleware({ dispatch }) {
  return next => action => {
    // ... various checks

    const [ requestType, successType, errorType ] = types;
    dispatch({ ...payload, type: requestType });

    return callApi().then(
      response => dispatch({ ...payload, type: successType, response }),
      error => {
          dispatch({ ...payload, type: errorType, error });
          throw error;
      }
    );
  }
}

使用undefined来实现Promise的原因是,这是中间件返回的内容:

return callApi().then(
  response => dispatch({ ...payload, type: successType, response }),
  error => dispatch({ ...payload, type: errorType, error })
);

由于它不会在第二个回调中抛出错误,因此可以实现最终的Promise。 由于它也不返回任何内容,因此可以使用undefined来实现。

在这种情况下,您可以更改代码以重新抛出错误:

return callApi().then(
  response => dispatch({ ...payload, type: successType, response }),
  error => {
    dispatch({ ...payload, type: errorType, error })
    throw error;
  }
);

这将提供您期望的结果,但每次请求失败时,都会在DevTools中报告未处理的拒绝。 在您的情况下可能很好。

至于第二个示例:

但是,这返回了一个非常大的错误,该错误告诉我派遣是不可行的,即不是承诺。

看起来.to.eventually.* 在Promises上起作用 确实, dispatch不是一个承诺,所以您不能像这样使用它。 您可能想编写如下代码:

return expect(promise).to.eventually.be.fulfilled.then(() => {
  expect(dispatch).to.be.calledTwice();
});

最后,我鼓励您查看Redux Saga 与自定义中间件相比,使用生成器描述副作用要容易得多,并且生成器更易于测试

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM