Node.js mocha测试:ReferenceError:未定义会话

时间:2016-04-12 11:02:54

标签: node.js unit-testing session mocha

我写了用于测试登录和注册系统的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)  

如何修复此错误?

1 个答案:

答案 0 :(得分:1)

您的会话对象在定义的测试范围内是本地的。因为mocha在之前调用会话对象,所以期望会话全局定义。

简单来说,将var session = {}移到define('AccountController')测试之外