【问题标题】:How to test node.js-mongodb app using Mocha, Chai and Sinon? I am having difficulty with Sinon part如何使用 Mocha、Chai 和 Sinon 测试 node.js-mongodb 应用程序?我对诗乃部分有困难
【发布时间】:2016-09-18 09:29:00
【问题描述】:

我是测试新手,在使用 Sinon 存根和模拟时遇到困难。 如何为以下 senario 编写“quote.list_quote”测试。

这里是路由文件:quotes.js

const express = require('express');
const request = require('request');
const async = require('async');
const validator = require('validator');

const quote_router = express.Router();

const confg = require("../../confg/confg");
const quote = require("../models/mquotes");
const quotes_model = quote.quotes;

// host name - needs to be set up using the environment variable
const hostname = confg.hostname;

// route for "quotes/"
quote_router.route("/")
// get route : display the random quote
.get((req, res) => {
    // display random quote
    async.waterfall([
            (callback) => {callback(null, {res});},
            quote.count_quotes
        ], check_quote_exist
    );
})
// post route : create a new quote
.post((req, res) => {
    const doc_json = {author : validator.escape(req.body.quote_author), quote_text : validator.escape(req.body.quote_text)};
    const params = {res, doc_json, quote_action : quote.create_quote};
    add_edit_quote(params);
})
// put route : edit the quote
.put((req, res) => {
    const doc_json = {author : validator.escape(req.body.quote_author), quote_text : validator.escape(req.body.quote_text)};
    const params = {res, doc_json, quote_action : quote.update_quote, qid : req.body.quote_id};
    add_edit_quote(params);
})
// delete quote : delete the quote
.delete((req, res) => {
    const qid = req.body.qid;
    const condition = {_id : qid};
    async.waterfall([
            (callback) => {callback(null, {res, condition});},
            quote.delete_quote
        ], request_quote_list
    );
});

// route for "quotes/list" : display quotes list
quote_router.get("/list/", (req, res) => {
    // mention the main operation 
    let operation;

    if(req.body.operation != 'undefined') {
        operation = req.body.operation;
    } else {
        operation = "list_quotes";
    }

    async.waterfall([
            (callback) => {callback(null, {res, operation});},
            quote.list_quote
        ], display_quotes_list
    );
});
// display the quotes list
const display_quotes_list = (err, params, quotes_list) => {
    if (err) {return console.log(err);}

    const res = params.res;
    const operation = params.operation;
    const header_msg = "List of all the quotes";
    let alert_msg;

    if(operation == "list_quotes")  {
        alert_msg = null;
    } else if(operation == "delete_quote")  {
        alert_msg = "Quote has been deleted";
    }

    const params_out = {
        page: "quote_list",
        title: 'Quotes Manager',
        host: hostname,
        header_msg,
        alert_msg,
        quotes_list
    };
    res.render('index', params_out);
};

// send http request for quote list page
const request_quote_list = (err, params) => {
    if (err) {return console.log(err);}

    const res = params.res;
    const operation = "delete_quote";

    request.get('http://' + hostname + '/quotes/list/', {json:{operation}},
        (error, response, body) => {
            if (!error && response.statusCode == 200) {
                res.send(body);
            }
    });
};

module.exports = quote_router;

这不是完整的文件。我只包含了其中的一部分。

她是模型文件:mquotes.js

const mongoose = require('mongoose');

// Define quote schema
const quoteSchema = new mongoose.Schema({
    author: String,
    quote_text: {type: String, required: true}
    },
    {timestamps: true}
);
const quote = {};

// Define quotes model
quote.quotes = mongoose.model('quotes', quoteSchema);

// error handler 
error_handler = (callback, err, params, return_value) => {
    if(err) { return callback(err);}
    else {callback(null, params, return_value);}
};

// add quote - create
quote.create_quote = (params, callback) => {
    const res = params.res;
    const doc_json = params.doc_json;
    quote.quotes.create(doc_json, (err, quotes_detail) => {
        error_handler(callback, err, {res, operation : 'create_quote'}, quotes_detail);
    });
};

// count the number of quotes
quote.count_quotes = (params, callback) => {
    quote.quotes.count({}, (err, quotes_count) => {
        error_handler(callback, err, params, quotes_count);
    });
};

// delete quote - delete - id
quote.delete_quote = (params, callback) => {
    quote.quotes.remove(params.condition, (err, query) => {
        error_handler(callback, err, params);
    });
};

// list quote - find
quote.list_quote = (params, callback) => {
    quote.quotes.find({}, (err, quotes_list) => {
        error_handler(callback, err, params, quotes_list);
    });
};

// find quote by id
quote.quote_by_id = (params, callback) => {
    quote.quotes.findById(params.qid, (err, quotes_detail) => {
        error_handler(callback, err, params, quotes_detail);
    });
};

// returns the detail of random quote
quote.random_qoute = (params, callback) => {
    const random_number = params.random_number;

    // select one quote after skipping random_number of times
    quote.quotes.findOne({}, (err, quotes_detail) => {
        error_handler(callback, err, params, quotes_detail);
    }).skip(random_number);
};

// update quote - update - id
quote.update_quote = (params, callback) => {
    const options = {new: true};
    const qid = params.qid;
    const update_json = params.doc_json;

    quote.quotes.findByIdAndUpdate(qid, {$set: update_json}, options, (err, quotes_detail) => {
        params.operation = 'update_quote';
        error_handler(callback, err, params, quotes_detail);
    });
};

module.exports = quote;

我已经在全球范围内安装了 mocha。现在,我想测试模型。我们以 quote.list_quote 函数为例。

const mongoose = require('mongoose');
const chai = require('chai');
const sinon = require('sinon');

const expect = chai.expect; // use the "expect" style of Chai
const mquotes = require('./../../app/models/mquotes');

describe('Tests for quote models', () => {
    describe("List quote", () => {
        it('list_quote() should return list of quotes', () => {

        });
    });
});

谁能告诉我我的编码实践。我的意思是我使用函数和模块的方式。

【问题讨论】:

    标签: mongodb unit-testing mocha.js sinon chai


    【解决方案1】:

    首先,您应该尝试使用statics 方法。之后,如果你想在猫鼬中使用Promise,你应该使用sinon-mongoosesinon-as-promised

    这是我使用 mocha、chai 和 sinon 测试的示例代码。希望对你有用。

    model.js

    var Schema = new mongoose.Schema({
        name: String,
        created_at: {
            type: Date,
            default: Date.now
        },
        updated_at: {
            type: Date,
            default: Date.now
        }
    });
    
    Schema.statics.findByName = function(name, cb) {
        this.findOne({
                name: name
            })
            .exec()
            .then(function getTemplate(template) {
                if (!template) {
                    var error = new Error('Not found template by name: "' + name + '"');
                    error.status = 404;
                    return cb(error);
                }
    
                return cb(null, template);
            })
            .catch(function catchErrorWhenFindByTemplateName(error) {
                error.status = 500;
                return cb(error);
            });
    }
    
    module.exports = mongoose.model('model', Schema);
    

    test.js

    var expect = require('chai').expect,
      sinon = require('sinon'),
      mongoose = require('mongoose');
    
    require('sinon-as-promised');
    require('sinon-mongoose');
    
    var Model = require('../../app/models/model');
    
    describe('Model', function () {
    
      describe('static methods', function () {
    
        describe('#findByName', function () {
    
          var ModelMock;
    
          beforeEach(function () {
            ModelMock = sinon.mock(Model);
          });
    
          afterEach(function () {
            ModelMock.restore();
          });
    
          it('should get error status 404 if not found template', function (done) {
            var name = 'temp';
            ModelMock
              .expects('findOne').withArgs({name: name})
              .chain('exec')
              .resolves(null);
    
            Model.findByName(name, function (error) {
              expect(error.status).to.eql(404);
              ModelMock.verify();
              done();
            });
    
          });
    
          it('should get message not found template if name is not existed', function (done) {
            var name = 'temp';
            ModelMock
              .expects('findOne').withArgs({name: name})
              .chain('exec')
              .resolves(null);
    
            Model.findByName(name, function (error) {
              expect(error.message).to.match(/Not found template by name/gi);
              ModelMock.verify();
              done();
            });
    
          });
    
          it('should get template when name is existed', function (done) {
            var name = 'temp';
            ModelMock
              .expects('findOne').withArgs({name: name})
              .chain('exec')
              .resolves('SUCCESS');
    
            Model.findByName(name, function (error) {
              expect(error).to.be.null;
              ModelMock.verify();
              done();
            });
          });
    
          it('should get error status 500 when model crashed', function (done) {
            var name = 'temp';
            ModelMock
              .expects('findOne').withArgs({name: name})
              .chain('exec')
              .rejects(new Error('Oops! Crashed'));
    
            Model.findByName(name, function (error) {
              expect(error.status).to.eql(500);
              ModelMock.verify();
              done();
            });
    
          });
    
        });
    
      });
    
    });
    

    【讨论】:

    • 非常感谢您为解决方案付出的努力。我和诗乃真的很难相处。这将是一个很大的帮助。
    猜你喜欢
    • 2017-06-09
    • 2015-12-01
    • 2021-09-27
    • 2018-11-05
    • 2021-01-01
    • 2017-10-08
    • 2018-02-27
    • 2018-04-08
    • 1970-01-01
    相关资源
    最近更新 更多