【问题标题】:How do I unit test the result of a 'then' of a promise in JavaScript?如何在 JavaScript 中对 promise 的“then”结果进行单元测试?
【发布时间】:2019-06-27 06:08:49
【问题描述】:

我正在使用 TypeScript 编写一个使用 AWS 开发工具包的非常简单的服务。我的 Jest 单元测试通过了,但覆盖率报告说“return result.Items”这一行没有被覆盖。谁能告诉这是为什么?这是开玩笑的错误吗?

// service file

/**
 * Gets an array of documents.
 */
function list(tableName) {
  const params = {
    TableName: tableName,
  };
  return docClient
    .scan(params)
    .promise()
    .then((result) => {
      return result.Items;
    });
}

// test file

const stubAwsRequestWithFakeArrayReturn = () => {
  return {
    promise: () => {
      return { then: () => ({ Items: 'fake-value' }) };
    },
  };
};

it(`should call docClient.scan() at least once`, () => {
  const mockAwsCall = jest.fn().mockImplementation(stubAwsRequest);
  aws.docClient.scan = mockAwsCall;
  db.list('fake-table');
  expect(mockAwsCall).toBeCalledTimes(1);
});

it(`should call docClient.scan() with the proper params`, () => {
  const mockAwsCall = jest.fn().mockImplementation(stubAwsRequest);
  aws.docClient.scan = mockAwsCall;
  db.list('fake-table');
  expect(mockAwsCall).toBeCalledWith({
    TableName: 'fake-table',
  });
});

it('should return result.Items out of result', async () => {
  const mockAwsCall = jest
    .fn()
    .mockImplementation(stubAwsRequestWithFakeArrayReturn);
  aws.docClient.get = mockAwsCall;
  const returnValue = await db.get('fake-table', 'fake-id');
  expect(returnValue).toEqual({ Items: 'fake-value' });
});

【问题讨论】:

    标签: javascript typescript unit-testing jestjs


    【解决方案1】:

    未涉及的行是传递给then 的成功回调。

    您的模拟将then 替换为一个不接受任何参数并且只返回一个对象的函数。代码中的回调在测试期间传递给 then 模拟,但它不会调用回调,因此 Jest 正确报告回调未包含在您的测试中。

    不要尝试返回一个 看起来Promise 的模拟对象,只需从你的模拟中返回一个实际解析的 Promise

    const stubAwsRequestWithFakeArrayReturn = () => ({
      promise: () => Promise.resolve({ Items: 'fake-value' })
    });
    

    ...这样then 仍将是实际的Promise.prototype.then,并且您的回调将按预期调用。


    您还应该await 返回的Promise 以确保在测试完成之前调用了回调:

    it(`should call docClient.scan() at least once`, async () => {
      const mockAwsCall = jest.fn().mockImplementation(stubAwsRequest);
      aws.docClient.scan = mockAwsCall;
      await db.list('fake-table');  // await the Promise
      expect(mockAwsCall).toBeCalledTimes(1);
    });
    
    it(`should call docClient.scan() with the proper params`, async () => {
      const mockAwsCall = jest.fn().mockImplementation(stubAwsRequest);
      aws.docClient.scan = mockAwsCall;
      await db.list('fake-table');  // await the Promise
      expect(mockAwsCall).toBeCalledWith({
        TableName: 'fake-table',
      });
    });
    

    【讨论】:

    • 谢谢!这是一个很好的答案,并且是注意到我忘记“等待”测试完成的道具。
    • @SimonStiph 不客气,很高兴听到它有帮助!
    【解决方案2】:

    Library chai-as-promised 值得一看。

    https://www.chaijs.com/plugins/chai-as-promised/

    而不是将您的期望手动连接到承诺的 完成和拒绝的处理程序。

    doSomethingAsync().then(
        function (result) {
            result.should.equal("foo");
            done();
        },
        function (err) {
           done(err);
        }
    );
    

    您可以编写表达您真正意思的代码:

    return doSomethingAsync().should.eventually.equal("foo");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-28
      • 1970-01-01
      • 1970-01-01
      • 2019-06-08
      • 2018-05-13
      • 2019-04-20
      • 2019-05-24
      • 2018-04-02
      相关资源
      最近更新 更多