2009-05-14 14 views
11

Sto scrivendo un test JUnit per un codice che produce un file Excel (che è binario). Ho un altro file di Excel che contiene il mio output previsto. Qual è il modo più semplice per confrontare il file effettivo con il file previsto?Il modo più semplice per confrontare due file Excel in Java?

Certo, potrei scrivere il codice da solo, ma mi chiedevo se esiste un metodo esistente in una libreria di terze parti attendibile (ad esempio Spring o Apache Commons) che già lo fa.

risposta

8

Ecco quello che ho finito per fare (con il lavoro pesante svolto dai DBUnit) :

/** 
* Compares the data in the two Excel files represented by the given input 
* streams, closing them on completion 
* 
* @param expected can't be <code>null</code> 
* @param actual can't be <code>null</code> 
* @throws Exception 
*/ 
private void compareExcelFiles(InputStream expected, InputStream actual) 
    throws Exception 
{ 
    try { 
    Assertion.assertEquals(new XlsDataSet(expected), new XlsDataSet(actual)); 
    } 
    finally { 
    IOUtils.closeQuietly(expected); 
    IOUtils.closeQuietly(actual); 
    } 
} 

Questo confronta i dati nei due file, senza il rischio di falsi negativi da qualsiasi metadati irrilevante che potrebbe essere diversa. Spero che questo aiuti qualcuno.

+0

Ehi, usare XlsDataSet da DBUnit è un'idea davvero intelligente; non ci ho pensato :-) – sleske

+0

L'ultima versione di DbUnit 2.5 non funziona con il file .xlsx, solo con i file .xls. Hai idea di come farlo funzionare per i file ".xlsx"? – Romain

+0

Nessuna idea scusa, a meno che tu non abbia la possibilità di esportare prima i file .xlsx in formato .xls. –

-1

Forse ... confrontare i digest MD5 di ciascun file? Sono sicuro che ci sono molti modi per farlo. Potresti semplicemente aprire entrambi i file e confrontare ogni byte.

EDIT: James dichiarato come il formato XLS potrebbe avere differenze nei metadati. Forse dovresti usare la stessa interfaccia che hai usato per generare i file xls per aprirli e confrontare i valori da una cella all'altra?

+2

Questa è una buona idea, tranne che non deve considerare se i file saranno identici (vale a dire che non c'è alcun metadati coinvolti, come ad esempio nel formato XLSX, per esempio. Questi diversi metadati produrranno ovviamente hash diversi). –

2

Si potrebbe utilizzare javaxdelta per verificare se i due file sono gli stessi. E 'disponibile da qui:

http://javaxdelta.sourceforge.net/

+0

Alla fine ho funzionato javaxdelta dopo aver passato in giro con la sua dipendenza dalla libreria "trove", ma sebbene funzioni come pubblicizzato, sleske ha ragione che ho bisogno di un confronto canonico, non di un confronto byte per byte. Grazie comunque per il suggerimento, che ho votato. –

0

appena scoperto che c'è qualcosa in commons-io di FileUtils. Grazie per le altre risposte.

+1

Questo in realtà non risolve il mio problema, in quanto sembrano esserci differenze tra i file di Excel che non sono dovuti a differenze di contenuto di geniune. Proverò a suggerire Sleske di analizzare i contenuti dei file e fare un confronto canonico. –

6

Un confronto semplice file può essere fatto facilmente utilizzando alcuni checksum (come MD5) o solo la lettura di entrambi i file.

Tuttavia, come i file di Excel contengono carichi di metadati, i file non sarà probabilmente mai essere identici byte per byte, come James Burgess ha sottolineato. Quindi avrai bisogno di un altro tipo di confronto per il tuo test.

mi consiglia di generare in qualche modo una forma "canonica" dal file di Excel, vale a dire la lettura del file Excel generato e convertirlo in un formato più semplice (CSV o qualcosa di simile), che manterrà solo le informazioni che si desidera controllare . Quindi è possibile utilizzare la "forma canonica" per confrontare con il risultato atteso (anche in forma canonica, ovviamente).

Apache POI potrebbe essere utile per la lettura del file.

BTW: lettura di un intero file per verificare le sue correctnes sarebbero generalmente non essere considere una prova di unità. Questo è un test di integrazione ...

+0

Hai ragione, stavo usando il termine unit test in modo approssimativo; in effetti è un test di integrazione gestito da JUnit. Lo aggiusterò ora. –

+0

Grazie per avermi messo sulla strada giusta; vedi la mia soluzione DBUnit sotto (o sopra, a seconda dei voti!) –

+0

Per i file .xlsx: le somme MD5 saranno sicuramente diverse, ma le directory risultanti dalla decompressione di entrambi i file .xlsx dovrebbero essere identiche (sarebbe un modo migliore di ottenere il forma canonica) – golimar

0
+0

Due problemi: quel codice fa solo un confronto byte per byte, che come sottolinea sleske, isn ' Ideale per Excel. Inoltre, cercavo un metodo di utilità di terze parti, non un blocco di codice su alcuni forum che potrebbero funzionare o meno. Aggiornerò la domanda per chiarire questo punto. –

0

È possibile utilizzare Beyond Compare 3 che può essere avviato da linea di comando e supporta diversi modi per confrontare i file di Excel, tra cui:

  • Confrontando fogli Excel come tabelle di database
  • Controllo tutti i contenuti testuali
  • Controllo contenuto testuale con qualche formatore
+0

Gli strumenti da riga di comando sono brutti da invocare da Java (nel mio caso, JUnit). –

8

Si potrebbe considerare l'utilizzo del mio progetto simple-excel che fornisce un mazzetto di prosciutto Crest Matchers per fare il lavoro.

Quando fai qualcosa come il seguente,

assertThat(actual, WorkbookMatcher.sameWorkbook(expected)); 

Faresti vedere, per esempio,

java.lang.AssertionError: 
Expected: entire workbook to be equal 
    but: cell at "C14" contained <"bananas"> expected <nothing>, 
      cell at "C15" contained <"1,850,000 EUR"> expected <"1,850,000.00 EUR">, 
      cell at "D16" contained <nothing> expected <"Tue Sep 04 06:30:00"> 
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20) 

In questo modo, è possibile eseguirlo dal tuo test automatted e ottenere un feedback significativo, mentre stai sviluppando.

Si può leggere di più su di esso a this article on my site

+0

Se sei lo sviluppatore di questo progetto, dovresti probabilmente aggiungere una dichiarazione di non responsabilità in tal senso. –

+0

non so perché sia ​​importante, è un progetto OSS ... – Toby

+0

Perché oltre ad essere una buona forma, è una regola di questo sito, vedi http://stackoverflow.com/faq#promotion. –

4

avevo bisogno di fare qualcosa di simile e stava già utilizzando il Apache POI library nel mio progetto per creare i file di Excel. Quindi ho deciso di utilizzare l'interfaccia ExcelExtractor inclusa per esportare entrambe le cartelle di lavoro come una stringa di testo e ho affermato che le stringhe erano uguali. Esistono implementazioni sia per che per XSSF for .xlsx.

Dump a stringa:

XSSFWorkbook xssfWorkbookA = ...; 
String workbookA = new XSSFExcelExtractor(xssfWorkbookA).getText(); 

ExcelExtractor ha alcune opzioni per ciò che tutti dovrebbero essere inclusi nel dump stringa. Ho trovato di avere utili impostazioni predefinite di includere i nomi dei fogli. Inoltre include il contenuto del testo delle celle.

2

Il modo più semplice che trovo è usare Tika. Io uso in questo modo:

private void compareXlsx(File expected, File result) throws IOException, TikaException { 
    Tika tika = new Tika(); 
    String expectedText = tika.parseToString(expected); 
    String resultText = tika.parseToString(result); 
    assertEquals(expectedText, resultText); 
} 


<dependency> 
    <groupId>org.apache.tika</groupId> 
    <artifactId>tika-parsers</artifactId> 
    <version>1.13</version> 
    <scope>test</scope> 
</dependency> 
+0

Sembra buono, I probabilmente la userò la prossima volta! –

Problemi correlati