【问题标题】:how to stub callback result in sinon?如何在 sinon 中存根回调结果?
【发布时间】:2018-10-02 02:31:18
【问题描述】:

我是 nodejs 的新手。

如何存根作为回调的返回结果。

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

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

根据我对 java 的理解,这是我将如何进行测试的流程。

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

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

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)

我做对了吗?如何返回回调结果?


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();
     });    
});

【问题讨论】:

    标签: node.js unit-testing callback sinon


    【解决方案1】:

    恐怕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);
    
    ...
    

    希望对你有帮助

    【讨论】:

    • 我可以继续,但我面临另一个错误。 AssertionError: expected { Object (_headers, cookies, ...) } to have status code 200 but got [Function]我是否使用了正确的回复(let res = httpMocks.createResponse();)?
    • 我使用了错误的功能。我应该是res.statusCode.should.be.equal(200);,因为 res 有一个属性 statusCode。
    猜你喜欢
    • 2015-11-28
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 2014-07-12
    • 2020-07-23
    • 1970-01-01
    • 2016-09-13
    • 2017-05-04
    相关资源
    最近更新 更多