2013-01-10 14 views
5

ho una classe che consumano un file XML e produrre output di testo in base all'input. Sia l'input che l'output sono piuttosto complessi e l'output può includere anche le cose non nell'input: ad es. include timestamp e i risultati dei dati in tempo reale che non sono controllati dall'input - con altre parole: la classe non è una trasformazione di input-output pura.Come abbinare testo contro i modelli in unità di test

Vorrei testare l'output di testo risultante utilizzando JUnit. Poiché il testo prodotto può variare in molti modi diversi in base all'input, mi piacerebbe essere in grado di abbinare parti specifiche dell'output a una sorta di modello in ogni test. Ogni modello dovrebbe consentire per alcuni semplici sostituzioni di testo e anche per gli intervalli nel testo che dovrebbe non essere abbinato.

La questione è se tali quadri esiste già?

Una possibilità di livello molto basso sarebbe utilizzare alcune espressioni regolari fantasiose per abbinare il testo, ma penso che saranno un po 'troppo limitate per il nostro utilizzo in quanto non si dispone di un contesto sufficiente nelle espressioni regolari ...

EDIT: Due commenti:

  • una delle funzioni della classe è la capacità di fare certe semplici tipi di aggregazione di dati e calcoli (ad esempio somme) sulla base di input. Mi piacerebbe testare, senza testare anche il resto del testo generato.
  • vorrei che fosse possibile apportare modifiche al codice di base esistente, ma è un grande mandrino di codice legacy che davvero non voglio refactoring. Quindi l'introduzione di servizi di simulazione o test di pezzi più piccoli non sarà possibile.
+0

Un'altra possibilità è rendere l'ambiente del test dell'unità più controllato fornendo un finto feed di dati in tempo reale che non cambia mai. – dasblinkenlight

+0

@dasblinkenlight Sfortunatamente, questo non è possibile a meno che non apporti alcune modifiche massicce al codice ... comunque, mi piacerebbe essere in grado di testare i vari effetti di piccole modifiche nell'input - nel qual caso non voglio controlla il risultato completo, ma solo alcuni effetti localizzati ... –

+0

Forse è sufficiente testare se la parte che ti aspetti viene trasformata e da qualche parte nel testo. Se non sta cambiando, puoi semplicemente usare 'xml.contains (" la tua stringa ")'. Lo sto facendo in una situazione simile. – cringe

risposta

1

vorrei utilizzare Groovy per scrivere i test di unità, perché questo è uno di forza di Groovy, vedere

Ma Groovy è anche superbo per la gestione di XM L, vedere

Un piccolo esempio per sommare un po 'di attributi XML:

// multiline string, very complex XML content :-) 
def input = '''\ 
<list> 
    <summand value='13' time='10:40' text='Compare me!'/> 
    <summand value='1' /> 
    <summand value='4' /> 
    <summand value='2' /> 
    <summand value='7' /> 
</list>''' 

// reading XML via XmlSlurper 
def list = new XmlSlurper().parseText(input) 

// Prints 13 
println list.summand[0][email protected] 

// collect all summand values, prints 27 
println list.summand.collect { [email protected]() }.sum() 

È possibile trovare un buon tutorial su test in MEAP Making Java Groovy o cercare a questo presentation.

Groovy ha anche template support.Ma con il supporto XML è molto facile confrontare solo determinati attributi e non l'intero contenuto del tag per saltare alcuni attributi come il timestamp che hai menzionato. Pertanto non è necessario confrontare i modelli. Per un esempio aggiungere questa fonte al Skript sopra:

// compare the first summand tag, skipping the time attribute 
assert [list.summand[0][email protected](), list.summand[0][email protected]] == [13, 'Compare me!'] 

Per imparare Groovy, vi consiglio il Groovy Koans. Vedi anche Adding Groovy Tests to a Maven Java Project.

Aggiornamento:
non vorrei confrontare il XML uno contro l'altro, invece avrei singoli valori di unit test come desribed nella mia risposta. Ma se si va il modo completo vorrei utilizzare il seguente approccio:

  • ottenere l'XML dalla logica di business
  • rimuovere (valori non comparabili con Groovy) temporanei
  • generare un modello da GStringTemplateEngine (vedi link sopra), senza i valori non confrontabili
  • confrontare entrambi i XMLs via http://xmlunit.sourceforge.net/
    È possibile trovare un esempio di Updating XML with XmlSlurper alla fine della pagina.
+1

Usiamo già Groovy, quindi questo è un buon punto di partenza :-) –

+0

Ti premo la taglia in quanto la tua risposta è quella che è più vicina a una soluzione. Nota che in questo caso l'output non è XML, quindi la tua risposta non è perfetta :-) –

+0

Grazie mille! Ho aggiornato la mia risposta. – ChrLipp

2

Forse questo è indicativo che è necessario eseguire il test a un livello inferiore? cioè testare i componenti contribuenti piuttosto che l'intera produzione in massa. Spero che possiate organizzare il vostro codice/test in modo da poter fornire un insieme immutabile di input (magari usando il mocking dove necessario) e di conseguenza le uscite non cambieranno.

Alcuni test di alto livello sarebbero utili (per confermare l'integrazione dei risultati) e potresti farlo con un semplice confronto tra stringhe (solo per verificare che le cose vengano integrate correttamente) ma penso che lo sforzo dovrebbe essere a un livello più granulare.

Altrimenti ho il sospetto si consiglia uno strumento diff-like, e this library sembra che potrebbe essere utile.

+0

Vorrei che fosse possibile, ma è un grosso pezzo di codice legacy che davvero non voglio refactoring. –

+0

Grazie per i riferimenti a java-diff-utils. Potrebbe rivelarsi utile. –

0

Penso che ci siano troppe poche informazioni su ciò che è necessario ottenere, quale sia il formato di output del messaggio, ecc. Tuttavia, presumo che dal momento che stiamo parlando di test, si disponga di un'informazione sostanziale sui dati che vuoi testare il tuo codebase contro.

Se la classe produce un output stabile (vale a dire per lo stesso input produce sempre lo stesso output), allora forse si potrebbe voler creare una sorta di modello per il dato set di dati che si desidera testare (per esempio con Velocity). Applicheresti i dati che l'input alla tua classe contiene anche nel tuo modello. A seconda dell'output della classe testata, è possibile testare se contiene ciò che il modello ha prodotto o (se ciò non è fattibile) utilizzare uno strumento DIFF su ciò che il modello ha prodotto.

Se l'output è un testo leggibile dall'uomo, forse indicizzarlo con, per esempio, Lucene e cercare corrispondenze potrebbe essere la soluzione? In caso contrario, l'abbinamento con un risultato di modello o anche l'output predefinito con un algoritmo di ricerca fuzzy potrebbe essere un'opzione valida.

Una domanda a cui devi rispondere è se il refactoring della base di codici sottostante non sarà (soprattutto nel lungo periodo) un compito più economico.

Avete anche considerato di testare il comportamento del codice sottostante (con Mockito) invece di testare l'output? Immagino che questo sarà molto più difficile dal momento che si tratta di un codice legacy con cui hai a che fare, ma forse è fattibile? Potresti anche rinforzarti con il PowerMock, che consente di prendere in giro metodi statici e altre magie, solitamente a portata di mano con il codice legacy.

+0

Abbiamo preso in considerazione sia il refactoring del codice che il derisione di alcuni servizi, ma ciò sarà quasi impossibile per un numero di ragioni legate al business. –

0

Suggerisco di analizzare l'output XML con uno strumento che lo trasforma in un albero di oggetti. Quindi puoi valutare l'albero degli oggetti al posto della stringa XML e scrivere le tue affermazioni di asser solo sulle parti a cui sei interessato. Permette anche di eseguire test che non sono possibili con gli strumenti di stringa, ad es. contare il numero di elementi, ecc.

Se si dispone di un XSD dell'output, è possibile utilizzare ad esempio XMLBeans o JABX. Se non si dispone di un XSD, è possibile scrivere un automa basato su SAX o utilizzare le espressioni XPath per selezionare alcune parti dell'albero XML.

+0

Posso vedere dalla domanda che non è chiaro che l'output non sia XML, ma testo semplice: -/ –

+1

Oh, ho letto male questo. Non importa :) – Wolfgang

-1

È possibile utilizzare Mockito insieme a PowerMock per testare parti separate del codice, PowerMock consente di eseguire qualsiasi operazione, inclusa la sostituzione di nuova creazione di istanze con oggetti mock, simulazione/sostituzione di metodi e classi statici, privati, in breve, tutto. Questa combinazione dovrebbe dimostrarsi abbastanza potente da testare parti separate del codice senza dover testare il tutto.

Non penso che si possa chiamare qualcosa Test unità quando si esegue un file 1mb attraverso un flusso incontrollato con molte parti diverse, non si può veramente sapere cosa succede e dove è successo quando qualcosa si rompe.

Problemi correlati