2014-11-06 8 views
6

ho questo tipo di test moka:moka con nodejs affermare hang/timeout per assert (false) invece di errore

describe 'sabah', → 
    beforeEach → 
     @sabahStrategy = _.filter(@strats, { name: 'sabah2' })[0] 
      .strat 

    it 'article list should be populated', (done) → 
     @timeout 10000 
     strat = new @sabahStrategy() 
     articles = strat.getArticleStream('barlas') 
     articles.take(2).toArray((result)→ 
      _.each(result, (articleList) → 

       // I make the assertions here 
       // assert(false) 
       assert(articleList.length > 1) 
      ) 
      done() 
     ) 

Il problema è, ogni volta che faccio assert(false), il test si blocca finché il timeout, invece di dare un errore di asserzione, perché?

Edit:

Per esempio, se ho questi due test

it 'assert false', (done) → 
     assert(false) 
     done() 

    it 'article link stream should be populated', (done) → 
     @timeout 20000 
     articles = @sabahStrategy.articleLinkStream('barlas') 
     articles.pull((err, result)→ 
      console.log('here') 
      assert(false) 
      console.log('after') 
      assert(!err) 
      assert(result.length > 1); 
      _.each(result, (articleList) → 
       assert(articleList.link) 
      ) 
      done() 
     ) 

Il primo, dà l'errore asserzione come previsto, il secondo, tronchi here, e si blocca al assert(false) così after non viene mai registrato. Ha qualcosa a che fare con articles essendo uno streaming e l'asserzione è all'interno di un callback pull, questo è da highland.js API.

Risolto Modifica:

Quindi, secondo Paolo I risolto il problema con questo codice:

it 'article stream should be populated', (done) → 
     @timeout 30000 
     articles = @sabahStrategy.articleStream('barlas') 

     articles.pull((err, result) → 
      try 
       # assert false properly throws now. 
       assert(false) 
       assert(!err) 
       assert(result.length == 1) 
       assert(result[0].body) 
       assert(result[0].title || result[0].title2) 
       done() 
      catch e 
       done(e) 
     ) 

Edit2:

ho prodotto una versione semplificata del problema :

h = require('highland') 
Q = require('q') 

describe 'testasynchigh', → 
    beforeEach → 
     @deferred = Q.defer() 
     setTimeout((→ 
      @deferred.resolve(1) 
     ).bind(this), 50) 


    it 'should throw', (done) → 
     s = h(@deferred.promise); 
     s.pull((err, result) → 
      console.log result 
      assert false 
      done() 
     ) 

Vedo che la tua versione funziona davvero con @Louis, ma se coinvolgi promesse nel mix, la moka non può gestire il problema, quindi si bloccherà in questo esempio. Prova anche a commentare il assert false e vederlo passare.

Quindi, Louis, spero di aver attirato la tua attenzione, potresti spiegare il problema, e try catch sembra davvero brutto e spero che tu trovi una soluzione ragionevole a questo.

risposta

7

Perché è quello che stai dicendo che vuoi fare, quando aggiungi il callback 'done'.

Il modo per eseguire effettivamente questo test è chiamare return done(err) se l'asserzione fallirebbe, dove err è qualsiasi stringa o oggetto di errore che si desidera segnalare.

In primo luogo, quando la tua asserzione fallisce, il programma genera un'eccezione e non raggiunge mai done(), motivo per cui non vedi che viene chiamato. Questo è il modo in cui le asserzioni dovrebbero funzionare, tuttavia dal momento che ci si trova in un test asincrono, il risultato è che la richiamata non si attiva mai, motivo per cui si preme il timeout.

In secondo luogo, come la mia risposta originale ha detto err è qualsiasi errore che si desidera inviare dal test. Può essere un messaggio di errore stringa o una sottoclasse di oggetti Error on-on. Lo crei e poi lo passi a done() per indicare che il test è fallito.

Il modo migliore per strutturare il codice in un test asincrono consiste nell'utilizzare i test come semplici booleani anziché come asserzioni. Se vuoi davvero usare assert, quindi avvolgilo in un try..catch.Ecco un paio di esempi:

if(err) return done(err); // in this case, err is defined as part of the parent callback signature that you have in your code already. 

if(result.length < 1) return done('Result was empty!'); 

Infine, se si vuole veramente assert, allora si può:

try{ 
    assert(!err); 
}catch(e){ 
    return done(e); 
} 

sto chiamando return done(err) piuttosto che done(err) perché si ferma il resto del codice da eseguire , che è normalmente quello che vuoi.

+1

Ho scritto il codice Mocha per oltre due anni troppo, e * * in genere non è necessario rilevare eccezioni come quella che mostri nella tua risposta qui. ** Potrebbe benissimo essere che "highland.js" stia deglutendo l'eccezione o che abbia qualche particolarità riguardo a come gestisce le eccezioni nei suoi callback. Ma generalmente, Mocha è abbastanza capace di rilevare eccezioni, siano esse sincrone o asincrone. Basta eseguire 'it (" test ", function (done) {setTimeout (function() {throw new Error();}, 100);});' ('done' non viene chiamato e non è un errore.)' Mocha rileverà l'eccezione senza alcun problema. – Louis

+0

@Louis, intendi la deglutizione come descritto qui https://github.com/caolan/highland/issues/121, pensi che questo potrebbe essere il problema? – user3995789

+0

@ user3995789 Sì, penso che sia questo il problema. Ho provato il tuo ultimo snippet con RSVP (un'altra libreria di promessa) e ottenere gli stessi risultati di Q. Ho anche provato ad usare ".errors" di Highland (chiamata "ma non ho ottenuto nulla di questo." – Louis

0

Quando uso Highland.js con un super semplice test, Mocha cattura la mancanza di affermare senza alcun problema:

var _ = require("highland"); 
var fs = require("fs"); 
var assert = require("assert"); 

describe("test", function() { 
    it("test", function (done) { 
     var s = _([1, 2, 3, 4]); 
     s.pull(function (err, result) { 
      console.log(result); 
      assert(false); 
      done(); 
     }); 
    }); 
}); 

Questo suggerisce che il problema nel tuo esempio non è Mocha, nè Highland.js. Se l'oggetto articleLinkStream (o articleSream; sembra passare dallo snippet allo snippet) è un codice personalizzato, quindi forse quel codice è bacato e in realtà inghiotte le eccezioni piuttosto che lasciarle andare in cima allo stack.

+0

vedere ** Edit2 ** per favore. – user3995789

0

Per chiunque con lo stesso problema: Si dovrebbe fare in modo che done() viene chiamato anche dopo un'asserzione non riesce, come nel codice seguente:

try { 
    // your asserts go here 
    done(); 
} catch (e) { 
    done(e); 
} 
Problemi correlati