如何在 sinon 中存根回调结果?

how to stub callback result in sinon?

我是 nodejs 新手。

如何存根我的 return 结果,这是一个回调。

我知道在做测试时不应该访问数据库。

我正在控制器级别进行单元测试。

这是我根据 java 的理解进行测试的流程。

  1. 模拟请求和响应。
  2. 设置请求参数。
  3. 模拟 bookDAO.selectBook 以便它 return 用户定义的结果。因此不调用 DB.
  4. 验证/断言 return 结果的值。 (即响应必须是 200,JSON 格式,必须有列 BOOK_ID、BOOK_TITLE 等)

但是,我无法成功模拟我的函数。 运行 npm 测试后,这是我收到的错误。

2018-10-02T10:00:17.809   1) Book service
       1. should list a SINGLE Book /book/id GET:
     Error: selectBook cannot yield to '[object Object]' since no callback was passed. Received [XCV1234, function (result) {

                res.status(200).json({
                        message: format(message.DEFAULT_MSG, "GET", constant.MODULE_URL),
                        result: result
                });
        }]
      at throwYieldError (node_modules\sinon\lib\sinon\call.js:22:11)
      at Object.yieldToOn (node_modules\sinon\lib\sinon\call.js:167:13)
      at Object.yieldTo (node_modules\sinon\lib\sinon\call.js:156:31)
      at Function.spyApi.(anonymous function) [as yieldTo] (node_modules\sinon\lib\sinon\spy.js:416:61)
      at Context.it (test\controller\BookController.spec.js:47:17)

我做的对吗?我如何 return 回调结果?


bookController.js:

exports.getBook = (req, res) => {   

    //get from request
    const id = req.params.id;

    const params = [id];

    bookDao.selectBook(params, function (result) {

        res.status(200).json({
            message: format(message.DEFAULT_MSG, "GET", constant.MODULE_URL),
            result: result  
        });
    });
};

bookDao.js:

function selectBook(params, callback) {

    pool.open(connString, function (err, conn) {

        conn.queryResult(query.SQL_SELECT, params, function (err, result) {

            if (err) {
                console.error(err);
                return conn.closeSync();
            }

            var data = result.fetchAllSync();

            // only when successful then call closeSync
            result.closeSync(); 

            return callback(data);
        });

        conn.close();
    });
}

bookRest.js:

module.exports = (app) => {

    // map to controller
    const controller = require('../controller/bookController');

    app.route(constant.MODULE_URL + '/:id').get(controller.getbook);

    app.route(constant.MODULE_URL).put(controller.updateBooks);
};

bookController.spec.js:

process.env.NODE_ENV = 'test';

const sinon = require('sinon');
const chai = require('chai');
const chaiHttp = require('chai-http');
const should = chai.should();
const httpMocks = require('node-mocks-http');

let server = require('../../../main.js');

const bookController = require('../../../controller/bookController.js');
const bookDao = require('../../../dao/bookDao.js');

chai.use(chaiHttp);

let req = httpMocks.createRequest();
let res = httpMocks.createResponse();

describe('Book service', () => {    
    beforeEach(() => {
    });

    afterEach(() => {
    });

    it('1. should list a SINGLE Book /book/id GET', (done) => {

        req.params.id = "XCV1234";
        const selectbook = sinon.stub(bookDao, "selectbook");

        bookController.getbook(req, res);
        selectbook.yieldTo({BOOK_ID : "XCV1234"});

        res.should.have.status(200);
        res.should.be.json;
        res.body.should.be.a('object');

        res.body.result[0].should.include.keys(
            'BOOK_ID'
        );

        sinon.restore();
        done();
     });    
});

恐怕 yieldsTo 不是适合这种情况的方法。根据文档,此方法旨在针对在

中作为 属性 传递的回调
sinon.stub(jQuery, "ajax").yieldsTo("success", [1, 2, 3]);

jQuery.ajax({
  success: function (data) {
    assertEquals([1, 2, 3], data);
  }
});

为了解决你的问题,我们可以使用 yields 这样它会像:

...

// should be stubbed before `getbook` is called
sinon.stub(bookDao, "selectbook").yields({
  BOOK_ID: "XCV1234"
});

bookController.getbook(req, res);

res.should.have.status(200);

...

希望对您有所帮助