我如何使用sinon,mocha

时间:2018-12-26 01:25:29

标签: node.js unit-testing promise mocha sinon

我有以下实现。如何进行单元测试。我想确保processData仅在成功时调用一次,而handleDecryptError在错误时调用一次。

我的单元测试抛出一个错误,指出AssertionError: expected 0 to equal 1的{​​{1}}。

实施:

should.equal(getHandleDecryptErrorSpy.callCount, 1);

测试用例:

let getData = exports.getData = (err, res, param) => {

    ...

    return security.decryptJWE(jweParts[0], jweParts[1], jweParts[2], jweParts[3], jweParts[4], privatekey)
        .then(data => processData(data, param))
        .catch(error => handleDecryptError(error, param));
}

let handleDecryptError = exports.handleDecryptError = (error, param) => {
    log.error(message.ERROR_DECRYPTING.red, error);

    ..

    return;
}

let processData = exports.processData = (momData, param) => {

    log.info(message.SUCCESS.red);

    ...

}

4 个答案:

答案 0 :(得分:0)

如果您从updateTask.getData返回了承诺,则可以在测试中将其调用,并将断言放在该调用所附的then()中。现在,测试可以等待getData()解决,然后再尝试任何断言:

it('6. Response for data is empty string', () => { // don't pass done

   return updateTask.getData() // return this promise and mocha will handle it
   .then(() => {
        // assertions will now run at the right time
        should.equal( /* etc */)
   }

此外,如果您未通过done,则可以返回测试中的承诺,摩卡咖啡就会知道测试何时结束。

此外,由于您使用的是Sinon — Sinon有一个不错的assertion library,您可以像这样使用:sinon.assert.calledOnce(getDecryptJWESpy);。这将为您提供有关equal失败的更好消息。

答案 1 :(得分:0)

我认为您要做的就是等待诺言。使用async/await更容易:

it('6. Response for data is empty string', async () => {

    let getDecryptJWESpy = sinon.stub(security, "decryptJWE").resolves(message.ERROR_DECRYPTING);
    let getProcessDataSpy = sinon.spy(updateTask, "processData");
    let getHandleDecryptErrorSpy = sinon.spy(updateTask, "handleDecryptError");

    let response = {
        body: "",
        text: ""
    };

    try {
        await updateTask.getData(null, response, ["TASKID"]);
    } catch(ignore) {}

    should.equal(getDecryptJWESpy.callCount, 1);
    should.equal(getProcessDataSpy.callCount, 0);
    should.equal(getHandleDecryptErrorSpy.callCount, 1);
});

答案 2 :(得分:0)

您首先需要确定需要测试的内容以及测试用例的完成时间。同样,由于您的代码使用回调而不是异步等待,因此使用done()声明结果更容易。

成功后,通过必要的参数测试一次processData仅被调用

调用processData时成功测试完成

因此您的测试用例变为

it('6. Response for data is empty string', (done) => {
  let getDecryptJWESpy = sinon.stub(security, "decryptJWE").resolves(message.ERROR_DECRYPTING);
  let getHandleDecryptErrorSpy = sinon.stub(updateTask, "handleDecryptError");
  let getProcessDataSpy = sinon.stub(updateTask, "processData").callsFake(function fakeFn() {
    should.equal(getDecryptJWESpy.callCount, 1);
    should.equal(getProcessDataSpy.callCount, 1);
    should.equal(getHandleDecryptErrorSpy.callCount, 0);
    //The test is done only is this point is reached
    done();
  });

  let response = {
    body: "",
    text: ""
  };
  updateTask.getData(null, response, ["TASKID"]);
});

失败时,请测试是否仅使用必需的参数调用一次handleDecryptError

调用handleDecryptError时失败测试完成

因此您的测试用例变为

it('6. Response for data is empty string', (done) => {
  let getDecryptJWESpy = sinon.stub(security, "decryptJWE").resolves(message.ERROR_DECRYPTING);
  let getProcessDataSpy = sinon.stub(updateTask, "processData");
  let getHandleDecryptErrorSpy = sinon.stub(updateTask, "handleDecryptError").callsFake(function fakeFn() {
    should.equal(getDecryptJWESpy.callCount, 1);
    should.equal(getProcessDataSpy.callCount, 0);
    should.equal(getHandleDecryptErrorSpy.callCount, 1);
    //The test is done only is this point is reached
    done();
  });

  let response = {
    body: "",
    text: ""
  };
  updateTask.getData(null, response, ["TASKID"]);
});

按原样的代码可能无法正常工作,因为我尚未对其进行测试,但是根据我的说法,测试的结构应如上所述。

答案 3 :(得分:0)

我的第一个建议是在所有地方使用回调或Promise保持一致。由于security.decryptJWE使用诺言,因此我们将使getData也使用诺言。

let getData = exports.getData = (err, res, param) => {
  ...

  // add 'return' so `getData` returns promise
  return security.decryptJWE(jweParts[0], jweParts[1], jweParts[2], jweParts[3], jweParts[4], privatekey)
      .then(data => processData(data, param))
      .catch(error => handleDecryptError(error, param));
}

似乎您的测试用例想要测试是否调用handleDecryptError,因此您必须使用rejects而不是resolves。如果使用resolves,它将转到processData而不是handleDecryptError

it('6. Response for data is empty string', () => {

  let getDecryptJWESpy = sinon.stub(security, "decryptJWE").rejects(message.ERROR_DECRYPTING); // update to use rejects
  let getProcessDataSpy = sinon.spy(updateTask, "processData");
  let getHandleDecryptErrorSpy = sinon.spy(updateTask, "handleDecryptError");

  let response = {
      body: "",
      text: ""
  };

  return updateTask.getData(null, response, ["TASKID"]) // add 'return' and 'then'
    .then(() => { // alternatively, we can use `async/await`
      should.equal(getDecryptJWESpy.callCount, 1);
      should.equal(getProcessDataSpy.callCount, 0);
      should.equal(getHandleDecryptErrorSpy.callCount, 1);
    });
});

希望有帮助