2016-06-02 17 views
6

Al contrario di codice non-asserito con controlli developer-friendly personalizzati,duplicazione Node.js `affermazioni assert` in spec` expect`

class Some { 
    constructor(arg) { 
    if (Array.isArray(arg) && arg[0] === 'foo') 
     this.foobar = arg.concat('bar').join(''); 
    else 
     console.error('Bad Some constructor arg'); 
    } 
} 

codice attualmente testato è fortemente compresso con nodo assert asserzioni con ragionevolmente significativa message argomenti:

class Some { 
    constructor(arg) { 
    assert.deepEqual(arg, ['foo'], 'Some constructor arg'); 
    this.foobar = arg.concat('bar').join(''); 
    } 
} 

L'affermazione è lì per

  • mantenere il codice piatta e leggibile
  • forniscono un feedback significativo sulla uso scorretto con stack di chiamate
  • impedire l'esecuzione la funzione e non si propagano l'errore più
  • generare un errore e lasciare la gestione degli errori al chiamante

spec attuale può sembrare che:

it('...',() => { 
    let some = new Some(['foo']); 
    expect(some).to... 

che ti passa - utilizzo desiderabile si afferma nelle specifiche, l'utilizzo indesiderato è affermato nel codice testato.

a sovrapporsi affermazioni di codice in parte potrebbe essere ancora

it('...',() => { 
    const { AssertionError } = require('assert'); 
    let some = new Some(['foo']); 
    expect(some).to... 
    expect(() => new Some(['bar']).to.throw(AssertionError); 

Così abbiamo praticamente per scontato qui che la metà dei posti di lavoro test è stato già fatto nel codice stesso con assert e saltare i dettagli (to.not.throw e la congruenza AssertionError messaggi).

L'esempio precedente utilizza Mocha + Chai, ma la stessa cosa vale per Jasmine.

  • caso App asserzioni essere trattati come qualsiasi altro righe di codice e ha raddoppiato con asserzioni spec (di gettare, a non gettare, AssertionError messaggio di corrispondenza), quali sono le conseguenze di prendere una scorciatoia?

  • È possibile verificare gli strumenti di copertura (Istanbul) tenendo conto delle asserzioni assert nel codice app oltre a expect?

  • I test runner possono essere confusi dal fatto che si tratta di un'app, non di un'asserzione che ha generato un errore?

Alcuni esempi di progetti JS open-source di successo che dimostrano o rifiutare 'affermano asserire affermazioni' punto, in pratica, potrebbe essere anche utile.

risposta

1

Se le asserzioni di app vengono trattate come qualsiasi altra riga di codice e raddoppiate con asserzioni di specifiche (per lanciare, non lanciare, AssertionError message matching), quali sono le conseguenze di una scorciatoia?

Le affermazioni di app servono a comunicare a uno sviluppatore l'uso non corretto di un determinato pezzo di codice, idealmente non accadrà mai in produzione.Se succede, servono come strumento per identificare ciò che è andato storto, nello stesso modo in cui lo fa l'errore standard. Ma idealmente, sono una prima linea di difesa durante lo sviluppo, e dovrebbero accadere solo allora. (quindi questa è una delle ragioni per cui in alcune lingue è possibile disabilitare le asserzioni per il tempo di esecuzione tutte insieme)

Se si scrive una classe che utilizza asserzioni per assicurarsi che i parametri di input siano convalidati o che il programma non sia utilizzato in modo incoerente, allora di sicuro ha molto senso mettere questa logica anche nei test unitari. Se cambierai le asserzioni ad un certo punto, vorresti essere in grado di verificare che non infrangi il codice degli altri.

È possibile verificare gli strumenti di copertura (Istanbul) tenendo conto di asserzioni nel codice app oltre a prevedere?

Sì. Se si imposta un test unitario che attiverà un'asserzione e quindi verrà acquisita in chai, il percorso del codice verrà visualizzato nel report di copertura. Questo non è diverso da qualsiasi altro percorso di codice, a meno che non capisco male la tua domanda.

I test runner possono essere confusi dal fatto che si trattasse di un'app, non di un'asserzione che ha generato un errore?

Quando si scrive asserzioni utilizzando il modulo assert, sta andando essere gettando un AssertionError. Questa è la classe AssertionError dal modulo assert. Quando chai lancia un errore, lancia anche un AssertionError, ma questa sarà una classe completamente diversa proveniente dal modulo chai, condividono solo il nome. Come tale non dovrebbe esserci alcuna confusione su da dove le asserzioni sono originate da.
Di solito non si stanno acquisendo asserzioni nel codice di test con tutti i costrutti try/catch così questo non dovrebbe essere un problema.

Di solito le asserzioni testano stati molto meno complessi quindi test di unità. Ma dove terminano le asserzioni e che i test unitari dovrebbero iniziare, non sono definiti in modo formale. Più lettura:

https://softwareengineering.stackexchange.com/questions/18288/are-asserts-or-unit-tests-more-important

+0

Grazie per la lettura, non risponde alla domanda ma lo integra. Bene su 'AssertionError', l'errore del nodo può essere confuso con l'errore Chai. Potrebbe non essere un problema reale, perché l'asserzione è asserzione (anche Sinon ha una classe di errore di asserzione). Oppure potrebbe diventare un problema quando appare la domanda 'where's 'expect' for that error'. Sono abbastanza sicuro che questa parte possa essere corretta tramite 'chai.AssertionError.prototype.name'. – estus

+0

@estus: non preoccuparti di dove proviene l'errore. I reporter di Mocha possono eseguire il dump di una traccia di stack (quella di default) in modo da poter individuare esattamente l'origine dell'errore. Faccio molta refactoring a seconda degli errori di test di Mocha per dirmi dove ho dimenticato di modificare qualche pezzo di codice. – slebetman

+0

Thx @estus Ho aggiornato la mia risposta per includere anche la domanda relativa a Istanbul. C'è qualcos'altro che posso aiutarti a capire ulteriormente? –

1

caso app asserzioni essere trattato come tutti gli altri righe di codice e ha raddoppiato con asserzioni spec (per gettare, di non gettare, AssertionError messaggio di corrispondenza), quali sono le conseguenze di prendere una scorciatoia?

Non lo consiglio. È come testare un test: sebbene tecnicamente sia possibile, in genere non lo fai perché non ne vale la pena.

È possibile verificare gli strumenti di copertura (Istanbul) tenendo conto di asserzioni nel codice app oltre a prevedere?

Qual è il comportamento che desideri ottenere? Con unit test questo è abbastanza chiaro su meassure: si esegue il test e si controlla quale codice viene visitato. Ma cosa ti piacerebbe fare con assert (nel codice)? Se la dichiarazione di affermazione viene raggiunta da qualche test unitario, beh, ovviamente il codice è coperto dal test. Se non lo è, dovrebbe essere considerato un codice attorno alla dichiarazione di asserzione come coperto dal test? Quanto del codice vorresti conteggiare come coperto? Tutto diventa veramente cattivo e non credo che esista una soluzione adeguata per questo.

Inoltre, l'intera metrica coperta dai test è almeno puzzolente - il solo fatto che esista un test che raggiunge un certo codice ti dice così poco sulla sua correttezza!

I test runner possono essere confusi dal fatto che si trattasse di un'app, non di un'asserzione che ha generato un errore?

Questo è stato (IMO correttamente) ha risposto da William. O manca qualcosa? :)

+0

Dall'approccio "non testare il tester", mi aspetto che Istanbul consideri le linee "assert" coperte (la copertura del 100% può essere solo un numero, ma indica qualcosa quando è inferiore a 100). [Questo problema] (https://github.com/gotwarlost/istanbul/issues/290) mi convince infine che questo non sarà un problema per Istanbul. – estus

0

vi consiglio generalmente due approcci che a mio avviso si occupa di questo:

  1. fare il test in test di unità (lo so che non è la stessa di asserzione fase di esecuzione, ma è possibile verificare che il vostro robustezza lavora in unit test)

  2. Struttura il codice, in modo che le condizioni di uscita si verificano prima e return. Quindi hai uno spazio piatto (non indentato) in cui scrivere il tuo codice di post-validazione. Se lo desideri, puoi scrivere il tuo logger/handler o "middleware del chiamante" per interrompere l'esecuzione per errori fatali.

+0

Non so come dovrebbe essere il 2, una porzione concisa di codice sarebbe utile. – estus