我昨天和今天早上一整天都在试图通过伪造/嘲笑/存根用户模型中的猫鼬调用来正确设置用户控制器的心理模型。
我已经为我认为我需要的用户控制器的所有测试编写了脚手架,但正在努力使模拟工作。
目前我得到:
1) userController
getUserByID
should return a user if id is valid & the user exists:
TypeError: Cannot read property 'have' of undefined
at Context.<anonymous> (test/controllers/userController.spec.js:58:25)
将非常感谢一些指示..
userController.spec.js
var expect = require('chai').expect;
var assert = require('chai').assert;
var should = require('chai').should;
var sinon = require('sinon');
const userModel = require('../../models/user')
var userController = require('../../controllers/userController');
describe('userController', function() {
const mockResponse = (fake) => {
return {
send: fake
};
}
// this is just example how you can design the fake request, you can also add header property if your website needs one!
// I'm not even going to use any of these stuff inside request
const mockRequest = (session, body) => ({
session,
body,
});
before(() => {
});
after(() => {
//user.findById.restore();
//done();
});
describe('getUserByID', function() {
it('should throw error if no arg passed in', function() {
})
it('should return a user if id is valid & the user exists', async function() {
//fake a user document
var fake = sinon.fake.returns(
{
"id": 1,
"password": "userPassword",
"firstName": "userFirstName",
"lastName": "userLastName",
"email": "user@email.com",
"allergens": ["Tree", "Grass"],
"severity": "High",
"createdAt": Date.now
}
)
sinon.replace(userModel, 'findById', fake);
//const users = await userController.getUserByID(1);
const user = userController.getUserByID(1);
user.should.have.length(1);
})
it('should return 200 OK if id is valid & the user exists', function() {
})
it('should return 500 SERVER ERROR id is valid & the user does not exist', function() {
})
})
describe('getUserByEmail', function() {
it('no argument should throw error', function() {
})
it('valid email & user exists should return a user', function() {
})
it('valid email & user exists should return 200 OK', function() {
})
it('valid email & user does not exist should return 500 SERVER ERROR', function() {
})
})
describe('addUser', function() {
it('no argument should throw error', function() {
//assert the error code
})
it('user with email already exists, get 400 error', function() {
//assert the error code
})
it('user with email does not exist, should return user', function() {
//check user object has all the fields
})
it('user with email does not exist, should return 201 OK', function() {
//assert the response code is 201
})
it('valid email & user does not exist should return 500 SERVER ERROR', function() {
//assert the error code
})
})
describe('getProfile', function() {
it('no argument should throw error', function() {
//assert the error code
})
it('user found, response is 200 OK', function() {
//assert the response code is 200
})
it('user found, user is returned', function() {
//check user object has all the fields
})
it('valid email & user does not exist should return 500 SERVER ERROR', function() {
//assert the error code
})
})
describe('updateUser', function() {
it('no argument should throw 500 error', function() {
//assert the error code
})
it('user with email exists, response is 400', function() {
//assert the response code is 200
})
it('attempt to update password should fail with 400 error', function() {
//check user object has all the fields
})
it('valid user updated, response is 200 OK', function() {
//assert the error code
})
it('valid user updated, updated user is returned', function() {
//assert the error code
})
})
describe('deleteUser', function() {
it('no argument should throw 500 error', function() {
//assert the error code
})
it('user with id exists, response is 200', function() {
//assert the response code is 200
})
it('user with id exists, failed to delete', function() {
//assert the 500 error code
})
it('user with id does not exist, repsonse is 500', function() {
//assert the error code
})
})
})
用户控制器.js
// Provide the controller a link to the user model
const user = require("../models/user");
// For token generating and authentication
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
//Function to search users by ID
const getUserByID = async (req, res) => {
try {
const foundUser = await user.findById(req.params.id);
// Do not return user's password in JSON!
const returnUser = JSON.parse(JSON.stringify(foundUser));
delete returnUser.password;
res.status(200).json({ user: returnUser });
} catch (err) {
res.status(500).json({ error: err.message });
}
};
//Set-up mongoose.
const mongoose = require("mongoose");
//To silence depcraction warnings
mongoose.set('useCreateIndex', true);
const uniqueValidator = require("mongoose-unique-validator");
//Create a new schema for users
const Schema = mongoose.Schema;
const userSchema = new Schema({
password: {
type: String,
required: [true, 'Please add a password'],
},
firstName: {
type: String,
required: [true, 'Please add a first name']
},
lastName: String,
email: {
type: String,
required: [true, 'Please add an email address'],
unique: true,
uniqueCaseInsensitive: true
},
allergens: [{
type: String,
enum:["Tree", "Grass", "Weed", "Pollution"]
}],
severity: {
type: String,
enum: ["High", "Medium", "Low", "None"],
required: [true, "Please indicate the hayfever severity"]
},
createdAt: {
type: Date,
default: Date.now()
}
});
//Create model from the user schema
userSchema.plugin(uniqueValidator, {message: "Error, that {PATH} is already taken."});
const users = mongoose.model("user", userSchema, "user");
module.exports = users;
你的代码有几个错误。
- 如果你想使用
should
,你需要调用它。(参考资料(。 - 函数
getUserByID()
需要 2 个参数。 - 函数
getUserByID()
返回 Promise,无需将其分配给变量并检查值。 - 方法
Model.findById()
返回 Query,您需要exec()
该查询才能从查询中获取值。(参考资料(。 - 为了从
userModel
findById
存根方法,您需要创建存根,而不是替换它。
注意:我根据我上面的观点添加了很多评论,你可以检查第1点到第5点。
文件用户控制器.js
const user = require('./userModel');
// 2. This function request 2 arguments!
// 3. This function return Promise<void>.
const getUserByID = async (req, res) => {
try {
// 4. Do not forget to add .exec()
// https://mongoosejs.com/docs/api.html#model_Model.findById
const foundUser = await user.findById(req.params.id).exec();
const returnUser = JSON.parse(JSON.stringify(foundUser));
delete returnUser.password;
res.status(200).json({ user: returnUser });
} catch (err) {
res.status(500).json({ error: err.message });
}
};
module.exports = { getUserByID };
文件用户控制器.spec.js
// 1. You just need to pick one between expect, assert, should.
// For this example, we try should.
// https://www.chaijs.com/guide/styles/#should
require('chai').should();
const sinon = require('sinon');
const userController = require('./userController');
const userModel = require('./userModel');
describe('userController', function () {
describe('getUserByID', function () {
it('should return a user if id is valid & the user exists', async function () {
// Fake a user document.
const fakeUser = {
id: 1,
password: 'userPassword',
firstName: 'userFirstName',
lastName: 'userLastName',
email: 'user@email.com',
allergens: ['Tree', 'Grass'],
severity: 'High',
createdAt: Date.now,
};
// 5. Create stub userModel method findById.
const stubUserFindById = sinon.stub(userModel, 'findById');
stubUserFindById.returns({
exec: sinon.fake.resolves(fakeUser),
});
// Create fake function for res.status and res.status.json.
const fakeResJson = sinon.fake();
const fakeResStatus = sinon.fake.returns({
json: fakeResJson,
});
// Create dummy request: to satisfy getUserById input (1).
const req = { params: { id: 1 } };
// Create dummy response.
const res = {
status: fakeResStatus,
};
// 2. Function getUserById requires 2 arguments!
// 3. Function getUserById return Promise<void>, so no need to check the result.
await userController.getUserByID(req, res);
// But verify that stub & fake get called with correct parameter.
// Verify stub called.
stubUserFindById.calledOnce.should.equal(true);
// Verify stub called with correct arguments.
stubUserFindById.calledWith(req.params.id).should.equal(true);
// Verify fake res.status get called.
fakeResStatus.calledOnce.should.equal(true);
// Verify fake res.status called with argument 200.
fakeResStatus.calledWith(200).should.equal(true);
// Verify fake res.status.json called.
fakeResJson.calledOnce.should.equal(true);
// Verify fake res.status.json called with correct argument.
fakeResJson.args[0][0].should.be.an('object');
fakeResJson.args[0][0].should.have.property('user');
// Verify property password removed.
fakeResJson.args[0][0].user.should.not.have.property('password');
fakeResJson.args[0][0].user.should.have.property('id', fakeUser.id);
fakeResJson.args[0][0].user.should.have.property('firstName', fakeUser.firstName);
fakeResJson.args[0][0].user.should.have.property('lastName', fakeUser.lastName);
// And check other properties as well.
// Restore stub.
stubUserFindById.restore();
});
});
});
使用摩卡运行它。
$ mocha userController.spec.js
userController
getUserByID
✓ should return a user if id is valid & the user exists
1 passing (9ms)
$
希望这对你有帮助。