Unit test di output testuale

3

Recentemente sono diventato responsabile di uno strumento legacy che analizza il codice e fornisce un log come output. Come parte della suite JUnit per questo, ci sono ~ 100 test che si basano sulla corrispondenza corretta del log prodotto con un expected log statico.

Ora questo significa che se il formato del registro cambia, interromperà i test unitari. Ma non posso decidere se questa è una cosa buona o cattiva.

Pro:

  • Test unitari che hanno subito un errore fatemi sapere che qualcosa è cambiato

Contro:

  • I test devono essere aggiornati ogni volta che lo stile del registro viene modificato
  • Un confronto testo diretto è negativo per questo caso, perché il file di registro richiede tempi. Quindi, se una corsa non richiede esattamente il tempo previsto, il test fallisce.

Non posso fare a meno di pensare che questi test non dovrebbero essere eseguiti. Ma allo stesso tempo non voglio lasciare scoperto il processo del file di log.

Qual è la soluzione qui? Migliori test unitari? Nessun test unitario? Come posso farlo senza che i miei test siano così fragili?

Il log viene scritto su un file e non fa parte di alcun framework di registrazione (viene generato un file dopo l'esecuzione dello strumento, che indica all'utente quali file hanno fallito la convalida e perché).

    
posta Rossiar 17.07.2015 - 15:16
fonte

3 risposte

4

Soluzione a breve termine: lascia le cose come sono. I test scritti male e fragili sono molto, molto meglio che non test. Su una scala da "nessun test" a "prove così affidabili che ti fanno piangere e fai tutto il lavoro per te", la tua suite di test esistente è molto più vicina a "piangere" che a "niente".

Soluzione a medio termine: refactoring. È inconcepibile che lo strumento di analisi non abbia una rappresentazione intermedia dei suoi risultati, prima che si trasformi in un flusso di testo. Rendi pubblicamente accessibile questa rappresentazione e riscrivi i test per far valere le cose su quella rappresentazione, non sulla forma testuale. Fa schifo, ma devi farlo solo una volta, e da quel momento in poi la manutenzione sarà molto, molto più facile, anche quando cambi logici e nuovi casi verranno aggiunti.

    
risposta data 17.07.2015 - 15:20
fonte
1

If the format of the log changes at all, it will break the unit tests

Quando il codice cambia, interrompe i test unitari corrispondenti. Seguendo la tua logica fino all'estremo, eviterai di scrivere test.

Pensa all'obiettivo di quei test. Stai provando:

  • Che un metodo registra effettivamente qualcosa?

  • Che un metodo utilizza un modello di messaggio corretto?

  • Che un metodo utilizza valori appropriati per formattare il messaggio?

  • Che un metodo registra un messaggio specifico (ovvero un modello di messaggio formattato utilizzando i valori effettivi)?

Nei primi tre casi, è possibile utilizzare l'iniezione di dipendenza (DI) per iniettare un mock o uno stub di registrazione. D'altra parte, questo significa più codice e logica più complicata, quindi se sei abbastanza sicuro che il formato del registro non cambierà comunque nel prossimo futuro, questo potrebbe non essere una cosa pragmatica da fare. Nota che la maggior parte dei framework di registrazione rende molto semplice la sostituzione dei tuoi gestori durante i test , il che significa che l'approccio effettivo potrebbe essere molto più semplice dell'implementazione di DI.

Se in realtà stai verificando che i messaggi corrispondano a quelli attesi, allora la soluzione corrente risponde perfettamente ai requisiti. Quelle centinaia di test non sono unit test, ma test funzionali / di sistema; tuttavia, sono perfettamente validi nella loro forma attuale.

Considerare la registrazione come uno degli output del metodo che dovrebbe essere testato. Come si asserisce che il risultato effettivo di un metodo è uguale al valore atteso, si eseguono allo stesso modo le asserzioni sui log. Idealmente, nei test unitari, la superficie di test sarà molto piccola: inietterai un log di simulazione e creerai un Assert.Equals sui messaggi ricevuti dal mock, nello stesso modo in cui testerai un metodo che dovrebbe esportare i dati su un file hanno effettivamente fatto il suo lavoro senza dover effettivamente utilizzare il file system. Nei test funzionali e di sistema, la superficie di test potrebbe essere molto più grande e includere il file system attuale.

    
risposta data 17.07.2015 - 15:23
fonte
1

Il problema sottostante che stai incontrando è che stai provando tutto in una volta sola quando confronti due file di testo. Se qualche piccola cosa cambia, allora l'intero test fallisce ed è davvero noioso trovare la parte che si è rotta e poi ripararla.

Stai facendo test di sistema in jUnit. Non che non sia in grado di farlo (anche se esistono migliori framework di test per incorporare più tipi di test) ma è importante capire la distinzione tra i tipi di test e quello che stai facendo.

E sì, i test di sistema sono alcuni dei test più fragili che si possono fare.

Il primo passo per correggere ciò sarebbe invece la scrittura di un file di registro, utilizzare un framework di registrazione come Log4J e fare in modo che un appender personalizzato scriva il formato desiderato nel file finale.

Passando a un framework di registrazione, è quindi possibile utilizzare diversi appenders per diverse situazioni. Quando si esegue il test, è possibile avere il proprio appender di convalida. Ciò consentirebbe di esporre le informazioni che sono state inviate al logger nei test e verificare che le informazioni siano corrette - che quando si invia questo messaggio nel framework di registrazione, contenga queste informazioni. Questo è un test unitario.

Un altro test di unità consisterebbe nel convalidare che quando si inviano informazioni specifiche nell'appender "al file del cliente", le informazioni corrispondenti vengono formattate correttamente nel registro (e si prende in giro il log che viene scritto in modo tale da non uscire colpire il disco con il confronto). Ogni tipo di messaggio viene testato e il formato convalidato. Ciò consente di testare il formato separatamente dal prodotto completo. Se il formato cambia, lo correggi qui (piuttosto che in tutti gli altri test).

Potresti voler provare testNG che ha come obiettivi di progettazione la possibilità di separare le suite di test e le fasi di test (unità, integrazione, sistema) meglio di jUnit nel momento in cui è stato scritto testNG (jUnit è arrivato modi da allora). Ciò ti aiuterà a rendere i test unitari più facili da eseguire per gli sviluppatori (il che li renderà più probabili essere eseguiti).

    
risposta data 17.07.2015 - 16:14
fonte

Leggi altre domande sui tag