тихие ошибки в тестах мокко с функциями генератора

Я хочу протестировать функцию. В этой функции я использую Co с функцией генератора. Когда возникает ошибка, я ее ловлю и вызываю cb с ошибкой

В моем модульном тесте я делаю ложное утверждение, но мокко не сообщает об этом, просто истекает время ожидания:

//function to test

function start(data, cb) {
  co(function * coStart() {
    yield Promise.reject('err'); // yield error for sake of demo
  }).then(function(result){
    return cb(null, result);
  }).catch(function (err) {
    // we get here
    return cb(err);
  });
}

// mocha test

it('fails on incorrect data', function(done){
  MyModel.start({'foo': 'bar'}, function(err, res){
    assert.equal(err, 'err2'); //this fails but mocha just stops here and times out
    done();
  });
});

Очевидно, я делаю что-то не так здесь?

Я знаю, что вы можете вернуть обещание мокко и пропустить обратный вызов в тесте, но моя функция «старт» не может вернуть обещание, это похоже на промежуточное программное обеспечение, поэтому оно должно работать с обратным вызовом.


person Ernie    schedule 19.05.2016    source источник


Ответы (1)


Ваш код делает что-то похожее на это:

Promise.reject('err')
       .catch(() => {
         // throw another exception
         throw 'foo';
       });

То есть: в предложении .catch() генерируется другое исключение (в вашем случае исключение, вызванное assert.equal(err, 'err2')), синхронно, которое не обрабатывается (например, другим предложением .catch()). Это приведет к тому, что второе исключение будет проигнорировано (см. этот ответ для объяснения), но это остановит тестовый пример от завершение (строка done() никогда не достигается, поэтому тестовый пример истекает).

Если вам действительно нужна поддержка обратного вызова, вы можете обойти это, либо добавив еще одно предложение .catch() в start(), либо вызвав обратные вызовы асинхронно:

return setImmediate(function() { cb(null, result) });
...
return setImmediate(function() { cb(err) });
...

Но в идеале вы должны рассмотреть возможность полного удаления поддержки обратного вызова и просто передать промисы. Mocha поддерживает обещания из коробки, поэтому код будет выглядеть примерно так:

function start(data) {
  return co(function * coStart() {
    yield Promise.reject('err');
  });
}

it('fails on incorrect data', function(){
  return start({'foo': 'bar'}).then(function() {
    throw new Error('should not be reached');
  }, function(err) {
    assert.equal(err, 'err2');
  });
});
person robertklep    schedule 19.05.2016
comment
Спасибо, чувак, я наконец понял это сейчас! setНемедленно работает. Есть ли какие-либо последствия для использования этого, потому что это немного похоже на взлом «нормального потока» - person Ernie; 19.05.2016
comment
Есть несколько альтернатив, таких как dezalgo, которые вы могли бы использовать вместо этого, что может дать более чистый код. Я бы предпочел полное обещание решения, но я понимаю, что это не всегда вариант: D - person robertklep; 19.05.2016
comment
Спасибо! Я проверю это - person Ernie; 19.05.2016