Express:单元测试控制器,它调用模型mongoose模型而不真正调用数据库



我有一个由Express.js路由器调用的控制器。控制器本身称猫鼬模型。我需要在不调用数据库的情况下对控制器进行单元测试,并且独立于路由器。

Test可能应该测试res.json(err)res.json(result)响应。

页面控制器:

const pageModel = require('../model/page');
const pageController = {
/**
* Get all pages as a list
* 
* @param {*} req 
* @param {*} res 
* @returns {json} list of pages
*/
getList(req, res) {
pageModel.find({}, (err, result)=>{
if (err) {
res.json(err);
} else {
res.json(result);
}
});
}
};
module.exports = pageController;

页面型号:

const mongoose = require('mongoose');
// Page Schema
const pageSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
slug: {
type: String,
required: true,
unique: true
},
content: String,
createdIn: {
type: Date,
default: Date.now
},
updatedIn: {
type: Date,
default: Date.now
}
});
const pageModel = mongoose.model('page', pageSchema);
module.exports = pageModel;

测试:

const chai = require('chai');
const expect = chai.expect;
const mongoose = require('mongoose');
const PageModel = require('../../../../app/page/model/page');
const pageController = require('../../../../app/page/controller/page');
const sinon = require('sinon');
let sandbox = sinon.createSandbox();
describe('Page controller', () => {
describe('getList', () => {
it('should return result as json object', (done) => {

});
});
});

以下是我的问题的答案:

首先,我修改了控制器功能getList以发送错误状态

getList(req, res) {
PageModel.find({}, (err, result) => {
if (err) {
res.status(500).end();
} else {
res.json(result);
}
});
}

现在,测试将测试两件事。1-返回"1"的实例的结果;页面";它是json对象。2-错误

说明:

1-创建一个sinon沙箱

let sandbox = sinon.createSandbox();

2-模拟并定义:req,res,error。。等

let req = {
body: {
title: 'title',
slug: 'slug',
content: 'content'
}
};
let res = {};
let expectedResult;
let error = new Error({error: 'error message here'});

3-在每次测试之前,监视res.json和res.status(错误(并创建预期结果(可选(。每次测试后,恢复沙箱。

beforeEach(()=>{
res = {
json: sandbox.spy(),
status: sandbox.stub().returns({end: sandbox.spy()})
};
expectedResult = [{}, {}, {}];
});
afterEach(()=>{
sandbox.restore();
});

4-测试中。存根mongoose.Model而不是PageModel。通过这种方式,您可以确保mongoose不会调用数据库(这很重要,因为我们不进行集成测试(。然后确保已调用PageModel,并且控制器函数返回预期结果。

it('should return result/page as json object', (done) => {
sandbox.stub(mongoose.Model, 'find').yields(null, expectedResult);
PageController.getList(req, res);
sinon.assert.calledWith(PageModel.find, {});
sinon.assert.calledWith(res.json, sinon.match.array);
done();
});
it('should return error 500', (done) => {
sandbox.stub(mongoose.Model, 'find').yields(error);
PageController.getList(req, res);
sinon.assert.calledWith(PageModel.find, {});
sinon.assert.calledWith(res.status, 500);
sinon.assert.calledOnce(res.status(500).end);
done();
});

这是完整的代码:

const chai = require('chai');
const expect = chai.expect;
const mongoose = require('mongoose');
const PageModel = require('../../../../app/page/model/page');
const PageController = require('../../../../app/page/controller/page');
const sinon = require('sinon');
let sandbox = sinon.createSandbox();
describe('Page controller', () => {
let req = {
body: {
title: 'title',
slug: 'slug',
content: 'content'
}
};
let res = {};
let expectedResult;
let error = new Error({error: 'error message here'});

describe('getList', () => {
beforeEach(()=>{
res = {
json: sandbox.spy(),
status: sandbox.stub().returns({end: sandbox.spy()})
};
expectedResult = [{}, {}, {}];
});

afterEach(()=>{
sandbox.restore();
});

it('should return result/page as json object', (done) => {
sandbox.stub(mongoose.Model, 'find').yields(null, expectedResult);
PageController.getList(req, res);
sinon.assert.calledWith(PageModel.find, {});
sinon.assert.calledWith(res.json, sinon.match.array);
done();
});
it('should return error 500', (done) => {
sandbox.stub(mongoose.Model, 'find').yields(error);
PageController.getList(req, res);
sinon.assert.calledWith(PageModel.find, {});
sinon.assert.calledWith(res.status, 500);
sinon.assert.calledOnce(res.status(500).end);
done();
});
});
});

如果你发现这个答案有改进,请随时编辑答案或写下你自己的答案

最新更新