如何对JavaScript中的promise的“ then”结果进行单元测试?

时间:2019-02-03 05:33:40

标签: javascript typescript unit-testing jestjs

我正在使用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' });
});

2 个答案:

答案 0 :(得分:3)

未涵盖的行是传递给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',
  });
});

答案 1 :(得分:0)

chai-promise的图书馆值得一看。

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");