Javascript 断言forEach循环内的catch块代码

Javascript 断言forEach循环内的catch块代码,javascript,foreach,try-catch,sinon,sinon-chai,Javascript,Foreach,Try Catch,Sinon,Sinon Chai,我很难编写测试来断言catch块中发生的事情,而catch块是在forEach循环中执行的 产品代码 function doSomething(givenResourceMap) { givenResourceMap.forEach(async (resourceUrl) => { try { await axios.delete(resourceUrl); } catch (error) { logger.error(`Error on

我很难编写测试来断言catch块中发生的事情,而catch块是在
forEach
循环中执行的

产品代码

function doSomething(givenResourceMap) {
  givenResourceMap.forEach(async (resourceUrl) => {
    try {
        await axios.delete(resourceUrl);
    } catch (error) {
        logger.error(`Error on deleting resource ${resourceUrl}`);
        logger.error(error);
        throw error;
    }
});
我想断言
logger.error
被调用两次,每次都使用正确的参数调用。所以我写了一些这样的测试

describe('Do Something', () => {
  it('should log message if fail to delete the resource', function() {        
    const resource1Url = chance.url();
    const givenResourceMap = new Map();
    const thrownError = new Error('Failed to delete');
    givenResourceMap.set(resource1Url);

    sinon.stub(logger, 'error');
    sinon.stub(axios, 'delete').withArgs(resource1Url).rejects(thrownError);

    await doSomething(givenResourceMap);

    expect(logger.error).to.have.callCount(2);
    expect(logger.error.getCall(0).args[0]).to.equal(`Error deleting resource ${resource1Url}`);
    expect(logger.error.getCall(1).args[0]).to.equal(thrownError);
    // Also need to know how to assert about `throw error;` line
  });
});
我正在使用摩卡咖啡,西农柴,期待测试。上述测试失败,说明
记录器。错误为0次


谢谢。

问题在于,您正在对不返回承诺的函数使用
wait
。请注意,
doSomething
不是
async
,并且不返回
Promise
对象

forEach
函数是
async
,但这意味着它们将立即返回,并带有一个未解决的
承诺
,您永远不会
等待它们

实际上,
doSomething
将在
forEach
内部的工作完成之前返回,这可能不是您想要的。为此,可以使用如下常规for循环:

async function doSomething(givenResourceMap) {
  for (const resourceUrl of givenResourceMap) {
    try {
        await axios.delete(resourceUrl);
    } catch (error) {
        logger.error(`Error on deleting resource ${resourceUrl}`);
        logger.error(error);
        throw error;
    }
  }
}
请注意,它将
doSomething
的返回类型更改为
Promise
对象,而不是像最初那样仅返回
undefined
。但它确实允许您在测试中(可能也在生产代码中)根据需要对其执行
wait

但是,由于重新抛出循环中捕获的异常,测试将异常退出。测试代码也必须更改以捕获预期错误:

it('should log message if fail to delete the resource', function(done) { 
  // ... the setup stuff you had before...       
  await doSomething(givenResourceMap).catch(err => {
    expect(logger.error).to.have.callCount(2);
    expect(logger.error.getCall(0).args[0]).to.equal(`Error deleting resource ${resource1Url}`);
    expect(logger.error.getCall(1).args[0]).to.equal(thrownError);
    done();
  });
});


测试通过,即使prod代码中没有logger.error语句。我在测试中尝试了async/await,而不是done。您需要在
捕获
中使用您的Expect,因为您确实在错误上抛出了一个异常。
done
可能不是强制性的,但不会造成伤害。你现在有什么问题?如果考试通过,你会很高兴,对吗?