如何使用Mocha,Chai和Sinon测试node.js-mongodb应用程序?我对Sinon部分有困难

时间:2016-09-18 09:29:00

标签: mongodb unit-testing mocha sinon chai

我是新手测试并且遇到Sinon存根和模拟有困难。 我如何为" quote.list_quote'编写测试?跟随Senario。

这是路径文件: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', () => {

        });
    });
});

任何人都可以告诉我我的编码习惯。我的意思是我使用函数和模块的方式。

1 个答案:

答案 0 :(得分: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();
        });

      });

    });

  });

});