【问题标题】:Node.js axios unit testing using Mocha, sinon and chai使用 Mocha、sinon 和 chai 进行 Node.js axios 单元测试
【发布时间】:2026-01-21 23:15:01
【问题描述】:

我有 node.js 组件名称 controller.js,它有一个使用带有选项的 axios 调用 api 服务的函数,它还具有用于错误处理的 catch 函数。我无法存根 axios 函数以便通过单元测试来覆盖它。

下面是controller.js 组件。

const axios = require('axios');
export.getData = function(req, res, next) {
  try {
     const options = {
            method: 'GET',
            headers: headers,
            url,
            params: queryParams
     };  
     axios(options).then(function (response) {
            res.json(response.data);
        })
            .catch(function (error) {
                if (error && error.response) {
                    if (error.response.status === 401) {
                        res.status(500).send({ error: true, message: 'There seems to be an issue, please try after sometime' });                   
                    }
                 }
             });
  }
}

下面是我的controller.test.js

const chai = require('chai');
const assert = chai.assert;
const axios = require('axios');
const sinon = require('sinon');
const controller = require('../controllersr');

describe("controller API testing", () => {

it("should call getMarketId function and return status 200 on success", function (done) {
        const req = { };
        const res =  { json: {greet: "hello"}, status: 200};
        var mockStub = sinon.stub(axios, 'get').resolves(res);
        controller.getData(req, res);
        assert.equal(res.status, 200);
        mockStub.restore();
        done();
    });

});

在这里,我无法对 axios 函数和 catch 函数进行存根以进行错误处理。 因此无法覆盖纽约市 axios 成功和 catch 函数的代码。 请帮忙..

【问题讨论】:

  • 正确的 req = {} 对象在 controller.test.js 中发送
  • 您的代码正在调用 axios() 但您的测试正在存根 axios.get...这是两个不同的东西。即使你的存根有效,它也是存根错误的方法
  • 请提出任何解决方案来覆盖 axios(options) 方法及其在 NYC 代码覆盖中的捕获错误功能。
  • 您可以在代码中使用axios.get(url, {headers, params}) 而不是axios(options),它应该可以工作

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


【解决方案1】:

首先,你不能使用try...catch语句来捕获异步代码,如果你想这样做,你需要使用async/await来等待promise被解析或拒绝。此外,由于您已经捕获了axios 异常并且没有重新抛出它,因此您不需要try...catch

其次,您正在尝试存根 axios 函数,该函数是从 axios 模块导入的独立函数。诗乃不支持。您需要使用Link Seams,所以我们将使用proxyquire 来构造我们的接缝。

例如

controller.js:

const axios = require('axios');

exports.getData = function (req, res, next) {
  const options = {
    method: 'GET',
    headers: headers,
    url,
    params: queryParams,
  };
  axios(options)
    .then(function (response) {
      res.json(response.data);
    })
    .catch(function (error) {
      if (error && error.response) {
        if (error.response.status === 401) {
          res.status(500).send({ error: true, message: 'There seems to be an issue, please try after sometime' });
        }
      }
    });
};

controller.test.js:

const sinon = require('sinon');
const proxyquire = require('proxyquire');

describe('controller API testing', () => {
  it('should call getMarketId function and return status 200 on success', async () => {
    const req = {};
    const res = { json: sinon.stub(), status: 200 };
    const axiosStub = sinon.stub().resolves({ data: { greet: 'hello' } });
    const controller = proxyquire('./controller', {
      axios: axiosStub,
    });
    await controller.getData(req, res);
    sinon.assert.calledWithExactly(axiosStub, {
      method: 'GET',
      headers: {},
      url: 'http://localhost:3000/api',
      params: {},
    });
    sinon.assert.calledWithExactly(res.json, { greet: 'hello' });
  });
});

单元测试结果:

  controller API testing
    ✓ should call getMarketId function and return status 200 on success (1306ms)


  1 passing (1s)

---------------|---------|----------|---------|---------|-------------------
File           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------|---------|----------|---------|---------|-------------------
All files      |    62.5 |        0 |   66.67 |    62.5 |                   
 controller.js |    62.5 |        0 |   66.67 |    62.5 | 15-17             
---------------|---------|----------|---------|---------|-------------------

【讨论】: