2016-08-03 4 views
0

Я пытаюсь проверить конструктор в node.js, который использует асинхронный код, чтобы проверить функцию в нем. Я знаю, что асинхронный код работает, потому что я уже запускал его, прежде чем я включил функцию, как если бы я был конечным пользователем. In fact, I got it thanks to some user who answered another question I hadТестирование конструктора, который содержит асинхронный код

Функция

User конструктор имеет userRole элемент, а некоторые асинхронной код, который проверяет userType указанный против User.userTypes. Если найдено userType, this.userRole установлено на userType. Else, исключение исключается.

код выглядит следующим образом:

async.forEachSeries(
    User.userTypes, 
    function(user_type, callback) 
    { 
     if (user_type == userType) 
     { 
      this.userRole = user_type; 
      return; 
     } 
     if (user_type == User.userTypes[User.userTypes.length - 1]) 
     { 
      callback(helpers.invalidData("user_role")); 
      return; 
     } 
     callback(null); 
    }, 
    function(err) 
    { 
     if (err) 
     { 
      if (DEBUG) 
      { 
       console.log("Error from constructor..."); 
       console.log(JSON.stringify(err, null, '\t') + "\n"); 
      } 
      throw err; 
     } 
    } 
); 

Остальная часть конструктора выглядит следующим образом:

function User(id, email, displayName, password, userType, deleted, cb) 
{ 
    var DEBUG = true; 
    var error = null; 
    this.userID = id; 
    this.email = email; 
    this.displayName = displayName; 
    this.deleted = deleted; 
    var self = this; 
    async.forEachSeries(
     User.userTypes, 
     function(user_type, callback) 
     { 
      if (user_type == userType) 
      { 
       this.userRole = user_type; 
       return; 
      } 
      if (user_type == User.userTypes[User.userTypes.length - 1]) 
      { 
       callback(helpers.invalidData("user_role")); 
       return; 
      } 
      callback(null); 
     }, 
     function(err) 
     { 
      if (err) 
      { 
       if (DEBUG) 
       { 
        console.log("Error from constructor..."); 
        console.log(JSON.stringify(err, null, '\t') + "\n"); 
       } 
       throw err; 
      } 
     } 
    ); 
    if (User.connectedToDatabase) this._password = password; 
    else 
    { 
     bcrypt.genSalt(10, function (e, salt) { 
      bcrypt.hash(password, salt, function (e, hash) { 
       if (!e) 
       { 
        self._password = hash; 
        if (DEBUG) 
        { 
         console.log("this._password ==" + self._password); 
         console.log("this.userID == " + self.userID); 
        } 
        if (typeof cb === 'function') 
         cb(null, this); 

       } 
       else 
       { 
        console.log("Error occurred: "); 
        console.log(e); 
        if (typeof cb === 'function') 
         cb(e); 
       } 
      }) 
     }); 
    } 
} 

User.connectedToDatabase = false; 
User.BASIC = "basic user"; 
User.INVENTORY_MANAGEMENT = "inventory"; 
User.ADMIN = "admin"; 
User.userTypes = [ User.BASIC, User.INVENTORY_MANAGEMENT, User.ADMIN ]; 

User.prototype.userID = 0; 
User.prototype.email = null; 
User.prototype.displayName = null; 
User.prototype._password = null; 
User.prototype.userRole = User.BASIC; 
User.prototype.deleted = false; 

User.prototype.responseObject = function() { 
    return { 
     id: this.userID, 
     email: this.email, 
     displayName: this.displayName, 
     userType: this.userRole 
    }; 
} 

Мой тест

Я пишу test() функцию, которая принимает параметры для передачи User. Если User построен без ошибок, он вместе с некоторыми из его членов печатается на консоль. Иначе ошибка печатается. Вот код:

function test(email, name, pass, type) 
{ 
    try 
    { 
     var a = new User(Math.round(Math.random() * 32), 
      email, 
      name, 
      pass, 
      type 
     ); 
     console.log("Test user created: " + JSON.stringify(a.responseObject(), null, '\t') + "\n"); 
     console.log("User._password == " + a._password); 
     console.log("\n"); 
    } 
    catch (e) 
    { 
     console.log("User could not be created.\n" + JSON.stringify(e, null, '\t') + "\n"); 
    } 
    /*async.waterfall([ 
     function(callback){ 
      var a = new User(Math.round(Math.random * 32), 
       email, 
       name, 
       pass, 
       type); 
      callback(null, a); 
     }, 
     function(a, callback) { 
      console.log("Test user created: " + JSON.stringify(a, null, '\t') + "\n"); 
      console.log("User._password == " + a._password); 
      console.log("User.userID == " + a.userID); 
      console.log("\n"); 
      callback(null, a); 
     } 
    ], 
    function(err, results) 
    { 
     console.log("results of test: " + JSON.stringify(results, null, '\t')); 
     if (err) 
     { 
      console.log("User could not be created.\n" + JSON.stringify(err, null, '\t') + "\n"); 

     } 
    })*/ 

} 

Мои тестов являются следующие:

  1. UserType соответствующий первый элемент User.userTypes
  2. UserType сопрягая другой элемент User.userTypes (я выбрал последний)
  3. UserType не соответствует ни одному из User.userTypes

Во время выполнения, после создания нового пользователя, значение User._password - это значение по умолчанию, а не значение, которое для него имеет асинхронный код. Sample run Я подозреваю, что у меня есть ошибка async-sync, но я не смог ее исправить.

+1

** Не создавать сложные конструкторы **. Он просто просил (так много) проблем, так как вы вкладываете много кода в функцию, которую время от времени приходится вызывать. Если у вас есть тонна дополнительной работы, поместите ее в какой-то метод 'init' и позвоните позже. – ssube

+0

@ssube Как в вызове конструктора, либо из кода, который вызывает конструктор? асинхронно или синхронно? –

+1

Код в (или вызван) из самого конструктора.Конструктор должен брать параметры и убирать их для будущих запросов, но он не должен выходить за пределы сети и выполнять кучу асинхронной работы, которая потенциально может завершиться неудачей позже. То есть, у конструктора нет способа указать отказ без металирования, поэтому он никогда не должен полагаться на то, что может потерпеть неудачу позже. Если это так, вы можете иметь частично построенный объект, который по существу является неопределенным поведением (самое худшее, о чем мы знаем). – ssube

ответ

0

Получил это исправление, благодаря совету @ Берги.

Первое, что я сделал: в этом async.forEachSeries(), я сменил любые экземпляры this на self.

Вторая вещь, которую я сделал: заменил этот асинхронный код (который работал!) На синхронный код. Вместо этого:

bcrypt.genSalt(10, function (e, salt) { 
     bcrypt.hash(password, salt, function (e, hash) { 
      if (!e) 
      { 
       self._password = hash; 
       if (DEBUG) 
       { 
        console.log("this._password ==" + self._password); 
        console.log("this.userID == " + self.userID); 
       } 
       if (typeof cb === 'function') 
        cb(null, this); 

      } 
      else 
      { 
       console.log("Error occurred: "); 
       console.log(e); 
       if (typeof cb === 'function') 
        cb(e); 
      } 
     }) 
    }); 

Я просто сказал: this._password = bcrypt.hashSync(password, bcrypt.genSaltSync(10));, и все было хорошо!

Смежные вопросы