我写了用于测试登录和注册系统的mocha代码:
这是代码:
controllers/account.js
var AccountController = function(userModel, session, mailer) {
this.crypto = require('crypto');
this.uuid = require('node-uuid');
this.ApiResponse = require('../models/api-response.js');
this.ApiMessages = require('../models/api-messages.js');
this.UserProfileModel = require('../models/user-profile.js');
this.userModel = userModel;
this.session = session;
this.mailer = mailer;
};
module.exports = AccountController;
//gets the current session
AccountController.prototype.getSession = function() {
return this.session;
};
//sets the current session
AccountController.prototype.setSession = function(session) {
this.session = session;
};
//Creates cryptographically-strong pseudo random hash of the password
AccountController.prototype.hashPassword = function(password, salt, callback) {
// we use pbkdf2 to hash and iterate 10k times by default
var iterations = 10000,
keyLen = 64; // 64 bit.
this.crypto.pbkdf2(password, salt, iterations, keyLen, callback);
};
//log in method
AccountController.prototype.logon = function(email, password, callback) {
var me = this;
me.userModel.findOne({
email: email
}, function(err, user) {
if (err) {
return callback(err, new me.ApiResponse({
success: false,
extras: {
msg: me.ApiMessages.DB_ERROR
}
}));
}
if (user) {
me.hashPassword(password, user.passwordSalt, function(err, passwordHash) {
if (passwordHash == user.passwordHash) {
var userProfileModel = new me.UserProfileModel({
email: user.email,
firstName: user.firstName,
lastName: user.lastName
});
me.session.userProfileModel = userProfileModel;
return callback(err, new me.ApiResponse({
success: true,
extras: {
userProfileModel: userProfileModel
}
}));
} else {
return callback(err, new me.ApiResponse({
success: false,
extras: {
msg: me.ApiMessages.INVALID_PWD
}
}));
}
});
} else {
return callback(err, new me.ApiResponse({
success: false,
extras: {
msg: me.ApiMessages.EMAIL_NOT_FOUND
}
}));
}
});
};
//log off method
AccountController.prototype.logoff = function() {
if (this.session.userProfileModel) delete this.session.userProfileModel;
return;
};
//register method
AccountController.prototype.register = function(newUser, callback) {
var me = this;
me.userModel.findOne({
email: newUser.email
}, function(err, user) {
if (err) {
return callback(err, new me.ApiResponse({
success: false,
extras: {
msg: me.ApiMessages.DB_ERROR
}
}));
}
if (user) {
return callback(err, new me.ApiResponse({
success: false,
extras: {
msg: me.ApiMessages.EMAIL_ALREADY_EXISTS
}
}));
} else {
newUser.save(function(err, user, numberAffected) {
if (err) {
return callback(err, new me.ApiResponse({
success: false,
extras: {
msg: me.ApiMessages.DB_ERROR
}
}));
}
if (numberAffected === 1) {
var userProfileModel = new me.UserProfileModel({
email: user.email,
firstName: user.firstName,
lastName: user.lastName
});
return callback(err, new me.ApiResponse({
success: true,
extras: {
userProfileModel: userProfileModel
}
}));
} else {
return callback(err, new me.ApiResponse({
success: false,
extras: {
msg: me.ApiMessages.COULD_NOT_CREATE_USER
}
}));
}
});
}
});
};
//reset password method
AccountController.prototype.resetPassword = function(email, callback) {
var me = this;
me.userModel.findOne({
email: email
}, function(err, user) {
if (err) {
return callback(err, new me.ApiResponse({
success: false,
extras: {
msg: me.ApiMessages.DB_ERROR
}
}));
}
// Save the user's email and a password reset hash in session. We will use
var passwordResetHash = me.uuid.v4();
me.session.passwordResetHash = passwordResetHash;
me.session.emailWhoRequestedPasswordReset = email;
me.mailer.sendPasswordResetHash(email, passwordResetHash);
return callback(err, new me.ApiResponse({
success: true,
extras: {
passwordResetHash: passwordResetHash
}
}));
})
};
/*Users will invoke this method when they access a special web page using the “password reset” link
inside the email that they will receive after they perform the first step of the password reset
process*/
AccountController.prototype.resetPasswordFinal = function(email, newPassword, passwordResetHash, callback) {
var me = this;
if (!me.session || !me.session.passwordResetHash) {
return callback(null, new me.ApiResponse({
success: false,
extras: {
msg: me.ApiMessages.PASSWORD_RESET_EXPIRED
}
}));
}
if (me.session.passwordResetHash !== passwordResetHash) {
return callback(null, new me.ApiResponse({
success: false,
extras: {
msg: me.ApiMessages.PASSWORD_RESET_HASH_MISMATCH
}
}));
}
if (me.session.emailWhoRequestedPasswordReset !== email) {
return callback(null, new me.ApiResponse({
success: false,
extras: {
msg: me.ApiMessages.PASSWORD_RESET_EMAIL_MISMATCH
}
}));
}
var passwordSalt = this.uuid.v4();
me.hashPassword(newPassword, passwordSalt, function(err, passwordHash) {
me.userModel.update({
email: email
}, {
passwordHash: passwordHash,
passwordSalt: passwordSalt
}, function(err, numberAffected, raw) {
if (err) {
return callback(err, new me.ApiResponse({
success: false,
extras: {
msg: me.ApiMessages.DB_ERROR
}
}));
}
if (numberAffected < 1) {
return callback(err, new me.ApiResponse({
success: false,
extras: {
msg: me.ApiMessages.COULD_NOT_RESET_PASSWORD
}
}));
} else {
return callback(err, new me.ApiResponse({
success: true,
extras: null
}));
}
});
});
};
test/user-mock.js
var UserMock = function () {
this.uuid = require('node-uuid');
this.crypto = require('crypto');
this.User = require('../models/user.js');
this.seedUsersCount = 10;
this.users = [];
this.err = false;
this.numberAffected = 0;
};
UserMock.prototype.setError = function (err) {
this.err = err;
};
UserMock.prototype.setNumberAffected = function (number) {
this.numberAffected = number;
};
UserMock.prototype.seedUsers = function () {
for (var i = 0; i < this.seedUsersCount; i++) {
var passwordSaltIn = this.uuid.v4(),
cryptoIterations = 10000, // Must match iterations used in controller#hashPassword.
cryptoKeyLen = 64, // Must match keyLen used in controller#hashPassword.
passwordHashIn;
var user = new this.User({
email: 'Test' + i + '@test.com',
firstName: 'FirstName' + i,
lastName: 'LastName' + i,
passwordHash: this.crypto.pbkdf2Sync('Password' + i, passwordSaltIn, cryptoIterations, cryptoKeyLen),
passwordSalt: passwordSaltIn
});
this.users.push(user);
}
};
UserMock.prototype.getTestUser = function () {
return this.users ? this.users[0] : null;
};
UserMock.prototype.findById = function (id, callback) {
for (var i = 0, length = this.users.length; i < length; i++) {
if (this.users[i]._id === id) {
return callback(this.err, this.users[i]);
}
}
return callback(this.err, null);
};
UserMock.prototype.findOne = function (where, callback) {
for (var i = 0, length = this.users.length; i < length; i++) {
if (this.users[i].email === where.email) {
return callback(this.err, this.users[i]);
}
}
return callback(this.err, null);
};
UserMock.prototype.save = function (callback) {
return callback(this.err, this, this.numberAffected);
};
module.exports = UserMock;
test/mailer-mock.js
var MailerMock = function () { };
MailerMock.prototype.sendPasswordResetHash = function (email, passwordResetHash) { };
module.exports = MailerMock;
test/accounnt-controller-test.js
var AccountController = require('../controllers/account.js'),
mongoose = require('mongoose'),
should = require('should'),
uuid = require('node-uuid'),
crypto = require('crypto'),
User = require('../models/user.js'),
UserMock = require('./user-mock.js'),
MailerMock = require('./mailer-mock.js'),
ApiMessages = require('../models/api-messages.js');
describe('AccountController', function() {
var controller,
seedUsersCount = 10,
testUser,
userModelMock,
session = {},
mailMock;
});
beforeEach(function(done) {
userModelMock = new UserMock();
mailerMock = new MailerMock();
controller = new AccountController(userModelMock, session, mailerMock);
done();
});
afterEach(function(done) {
userModelMock.setError(false);
done();
});
it('Returns db error', function(done) {
userModelMock.setError(true);
userModelMock.seedUsers();
var testUser = userModelMock.getTestUser(),
testUserPassword = 'Password0';
controller.logon(testUser.email, testUserPassword, function(err, apiResponse) {
should(apiResponse.success).equal(false);
should(apiResponse.extras.msg).equal(ApiMessages.DB_ERROR);
done();
});
});
/*logon method*/
AccountController.prototype.logon = function(email, password, callback) {
var me = this;
me.userModel.findOne({ email: email }, function (err, user) {
if (err) {
return callback(err, new me.ApiResponse({ success: false, extras: { msg: me.ApiMessages.DB_ERROR } }));
}
if (user) {
me.hashPassword(password, user.passwordSalt, function (err, passwordHash) {
if (passwordHash == user.passwordHash) {
var userProfileModel = new me.UserProfileModel({
email: user.email,
firstName: user.firstName,
lastName: user.lastName
});
me.session.userProfileModel = userProfileModel;
return callback(err, new me.ApiResponse({
success: true, extras: {
userProfileModel:userProfileModel
}
}));
} else {
return callback(err, new me.ApiResponse({ success: false, extras: { msg: me.ApiMessages.INVALID_PWD } }));
}
});
} else {
return callback(err, new me.ApiResponse({ success: false, extras: { msg: me.ApiMessages.EMAIL_NOT_FOUND } }));
}
});
};
当我在终端中运行mocha
时,出现以下错误:
1) "before each" hook for "Returns db error"
0 passing (37ms)
1 failing
1) "before each" hook for "Returns db error":
ReferenceError: session is not defined
at Context.<anonymous> (D:\PhoneGap_Projects\login\www\server\test\account-controller-test.js:24:55)
at callFnAsync (C:\Users\Ajay Kulkarni-enEXL\AppData\Roaming\npm\node_modules\mocha\lib\runnable.js:338:8)
at Hook.Runnable.run (C:\Users\Ajay Kulkarni-enEXL\AppData\Roaming\npm\node_modules\mocha\lib\runnable.js:290:7)
at next (C:\Users\Ajay Kulkarni-enEXL\AppData\Roaming\npm\node_modules\mocha\lib\runner.js:298:10)
at Immediate._onImmediate (C:\Users\Ajay Kulkarni-enEXL\AppData\Roaming\npm\node_modules\mocha\lib\runner.js:320:5)
如何修复此错误?
答案 0 :(得分:1)
您的会话对象在定义的测试范围内是本地的。因为mocha在之前调用会话对象,所以期望会话全局定义。
简单来说,将var session = {}
移到define('AccountController')
测试之外