Come testare l'unità di un parser di un file?

5

Sto implementando un parser di metadati di file di immagine da tutti i formati. Voglio scrivere test per questo. Un modo banale per farlo è avere i file immagine di prova di tutti i formati come risorse per i test e in realtà leggerli come input. Questo approccio potrebbe funzionare, ma per quanto ho capito dalla metodologia di test unitario, i test unitari non dovrebbero eseguire I / O. È un buon modo per farlo o sono alternative?

    
posta Sanich 18.03.2018 - 09:01
fonte

5 risposte

9

I want to write tests for it.

Che cosa intendi testare?

I want to use TDD. I'm refactoring a parser and want to test the 'parse()' method.

Quindi l'obiettivo è quello di pulire le cose.

Direi che il refactoring del codice legacy non è conforme al 100% w / TDD.

Il codice errato limita il test.

Ancora più importante: l'intenzione di ripulirlo (l'unità - il motivo della modifica del codice) differisce dall'intenzione originale di consentire al codice di eseguire qualsiasi tipo di dominio aziendale.

passaggio 1

Vorrei iniziare con un test di integrazione sciatto che copre la maggior parte delle funzionalità.

Feed test input grezzi - ad es. quei file di risorse da 50 MB.
Chiedi solo risultati brillanti e ignora le cose interne.

In realtà è importante - l'astrazione del test più elevata è ciò che allenta le restrizioni di implementazione.

Ciò ti darà una rete di sicurezza in modo che tu possa aprire il codice per il refactoring senza timore.

passaggio 2

Una volta ottenuto ciò, sei pronto per entrare effettivamente in & refactoring.

Leggi il codice. Avvia piccolo . ( buon libro )

Cose come la formattazione del codice, la rimozione dello spazio bianco in eccesso, la rimozione dei prefissi delle variabili troppo prolissi.

Quindi vai alle modifiche strutturali - estrai metodi, interfacce, classi dove necessario.
E non solo dividere & conquistare - prova a combinare cose dove "ha senso" ™.

Solo con una struttura decente del codice sarai in grado di scrivere test unitari per unità isolate di funzionalità.

Se il test di integrazione che hai iniziato funziona abbastanza bene, non mi preoccuperei nemmeno di provare a creare una rete di test delle unità.

In entrambi i casi - la corretta struttura del codice ti condurrà in modo naturale & facile da fermare la giunzione di I / O.

Una volta che la rete dei test unitari è abbastanza strong - rimuovi i test di integrazione.
Oppure stub l'input allo stesso modo dei test unitari (sorta di test dell'integralizzazione degli svaluti).

    
risposta data 18.03.2018 - 11:46
fonte
4

as far as I understand from unit test methodology, tests shouldn't perform I/O

Devi distinguere il tipo di test di cui stai parlando:

  • se vuoi usare TDD con piccoli "write test" - "write code" - "refactor" , allora hai bisogno di test di unità molto rapidi, idealmente con piccoli set di dati e no I / O.

  • quando si desidera eseguire test di accettazione o integrazione, in particolare utilizzando diverse immagini esterne, quindi utilizzando file e amp; I / O non è perfetto, ma probabilmente richiesto.

Quindi decidi in base a quale tipo di test stai scrivendo.

    
risposta data 18.03.2018 - 10:31
fonte
4

This approach may work but as far as I understand from unit test methodology, unit-tests shouldn't perform I/O

Penso che tu stia trascurando l'elefante nella stanza qui: il tuo parser non dovrebbe eseguire I / O .

Il lavoro del parser sta analizzando i dati, non I / O su disco. Qualunque sia la lingua che stai usando, probabilmente ha il concetto di uno stream . È da qui che il tuo parser riceve i dati. E se questo è un FileStream o MemoryStream o anche std::cin non è la tua attività di parser.

Quindi torna ai tuoi test: non importa. I test avranno i dati per testare il parser. E se questo è scritto su disco in file separati o flussi di manifest resource o array di byte hardcoded ... non ha molta importanza. L'automazione CI deve essere in grado di lavorare con esso e questo è tutto ciò che devi sapere. Alla fine, i dati sono su disco. Dove altro sarebbe? Anche il tuo codice eseguibile viene caricato dal disco.

Quindi riassumendo: rendi il tuo parser indipendente dall'accesso al disco. Separazione degli interessi. Quindi i tuoi test caricano i dati nel modo più elegante per la tua soluzione CI, in modo che i test non falliscano quando qualcuno li esegue sulla loro macchina (qualcun altro potrebbe anche essere il tuo agente CI). Come ottieni questo è un dettaglio a cui a nessuno interessa davvero finché funziona.

    
risposta data 19.03.2018 - 18:52
fonte
1

Durante il test dei parser, sono necessarie almeno due modalità di test:

  • Test nel micro: il parser sa come analizzare una frase (un insieme di byte o caratteri)
  • Test nella macro: il parser deve analizzare un intero insieme di frasi

Se il tuo parser è modale, avrai dei test per assicurarti che le transizioni di modalità siano gestite correttamente.

La linea di fondo è che si tratta di due diversi set di test. Di solito finisco per suddividere il lavoro in questo modo:

  • I test unitari servono per testare singole frasi
  • I test di integrazione servono per testare interi file e casi problematici

Normalmente posso impostare i byte in memoria per i micro test e usare il filesystem per i test di integrazione. Questo mi ha servito bene. Detto questo, creare frasi di prova per i parser testuali (la maggior parte di ciò che ho fatto) è molto più facile che fare lo stesso per i parser binari. Ho fatto un po 'di analisi binaria, quindi il mio test case avrà probabilmente degli array magici di byte, ma funziona.

    
risposta data 19.03.2018 - 17:32
fonte
1

Se ti ho capito correttamente, hai due obiettivi

  • aggiungi nuove funzionalità / funzionalità / refactoring al codice esistente
  • Durante l'estensione / rifrazione del codice esistente, assicurati che la funzionalità corrente non si interrompa (ovvero "test di regressione" o saftey net)

Se fossi in te, inizierei con la parte "assicurati che la funzionalità corrente non si rompa" come un test di integrazione basato su file con

  • una cartella di immagini di esempio
  • per ogni immagine c'è una rappresentazione testuale del risultato previsto.

Questo test di regressione (probabilmente lento) esegue iterazioni su tutti i file di immagine e confronta l'analisi con il file previsto.

Una volta che funziona, puoi iniziare a pensare a TDD con nuove funzionalità, che è qualcosa di completamente diverso dal test di regressione proposto.

Per la parte TDD della domanda non possiamo aiutarti senza vedere il codice. (la domanda è troppo ampia)

    
risposta data 19.03.2018 - 17:07
fonte

Leggi altre domande sui tag