2009-05-14 106 views
11

Estoy escribiendo una prueba JUnit para algún código que produce un archivo Excel (que es binario). Tengo otro archivo de Excel que contiene mi resultado esperado. ¿Cuál es la forma más fácil de comparar el archivo real con el archivo esperado?¿La manera más fácil de comparar dos archivos de Excel en Java?

Claro que podría escribir el código yo mismo, pero me preguntaba si existe un método existente en una biblioteca de terceros de confianza (por ejemplo, Spring o Apache Commons) que ya lo haga.

Respuesta

8

Esto es lo que terminé haciendo (con el trabajo pesado que está realizando 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); 
    } 
} 

Esto se compara los datos de los dos archivos, sin riesgo de falsos negativos de los metadatos irrelevante que podría ser diferente. Espero que esto ayude a alguien.

+0

Oye, usar XlsDataSet de DBUnit es una idea realmente inteligente; no pensé en eso :-). – sleske

+0

La última versión de DbUnit 2.5 no funciona con el archivo .xlsx, solo con archivos .xls. ¿Tiene alguna idea de cómo hacer que funcione para los archivos ".xlsx"? – Romain

+0

No tengo idea, a menos que tenga la opción de exportar primero los archivos .xlsx al formato .xls. –

-1

Quizás ... compare los resúmenes MD5 de cada archivo? Estoy seguro de que hay muchas formas de hacerlo. Podrías abrir ambos archivos y comparar cada byte.

EDITAR: James indicó que el formato XLS podría tener diferencias en los metadatos. ¿Quizás debería usar la misma interfaz que usó para generar los archivos xls para abrirlos y comparar los valores de celda a celda?

+2

Esta es una buena idea, excepto que usted tiene que considerar si los archivos serán idénticas (es decir, que no hay ningún metadatos involucrados, como por ejemplo en el formato XLSX, por ejemplo. Esta metadata diferente, obviamente, producirá hashes diferentes). –

2

Puede usar javaxdelta para verificar si los dos archivos son iguales. Está disponible desde aquí:

http://javaxdelta.sourceforge.net/

+0

Eventualmente obtuve javaxdelta funcionando después de perder el tiempo con su dependencia de la biblioteca "trove", pero aunque funciona como se anuncia, sleske tiene razón en que necesito una comparación canónica, no una comparación de byte a byte. Gracias de todos modos por la sugerencia, que voté. –

0

Acabamos de descubrir que hay algo en commons-io de FileUtils. Gracias por las otras respuestas.

+1

Esto realmente no resuelve mi problema, ya que parece haber diferencias entre los archivos de Excel que no se deben a las diferencias de contenido geniune. Probaré la sugerencia de sleske de analizar los contenidos de los archivos y hacer una comparación canónica. –

6

Una simple comparación de archivos se puede hacer fácilmente usando algunos checksum (como MD5) o simplemente leyendo ambos archivos.

Sin embargo, como los archivos de Excel contienen montones de metadatos, los archivos probablemente nunca serán idénticos byte por byte, como señaló James Burgess. Así que necesitará otro tipo de comparación para su prueba.

Recomiendo de alguna manera generar un formulario "canónico" del archivo Excel, es decir, leer el archivo Excel generado y convertirlo a un formato más simple (CSV o algo similar), que solo conservará la información que desea verificar . Luego puede usar la "forma canónica" para comparar con su resultado esperado (también en forma canónica, por supuesto).

Apache POI puede ser útil para leer el archivo.

BTW: Leer un archivo completo para comprobar su corrección generalmente no se consideraría una prueba unitaria. Eso es una prueba de integración ...

+0

Tiene razón, estaba usando el término prueba unitaria sin apretar; de hecho, es una prueba de integración ejecutada por JUnit. Lo arreglaré ahora. –

+0

Gracias por ponerme en el camino correcto; vea mi solución DBUnit a continuación (o más arriba, según los votos) –

+0

Para archivos .xlsx: las sumas MD5 definitivamente serán diferentes, pero los directorios resultantes de descomprimir ambos archivos .xlsx deberían ser idénticos (esa sería una mejor manera de obtener el forma canónica) – golimar

0

Por favor, eche un vistazo a the site para comparar los archivos binarios, http://www.velocityreviews.com/forums/t123770-re-java-code-for-determining-binary-file-equality.html

Tigre

+0

Dos problemas: ese código es simplemente hacer una comparación byte por byte, que como señala sleske, no es Ideal para Excel. Además, estaba buscando un método de utilidad de terceros, no un bloque de código en algún foro que puede funcionar o no. Actualizaré la pregunta para aclarar esto. –

0

Es posible utilizar Beyond Compare 3 que se puede iniciar desde la línea de comandos y admite varias formas de comparar archivos de Excel, incluyendo:

  • Comparando las hojas de Excel como tablas de bases de datos
  • Comprobación de todo el contenido textual
  • Comprobación contenido textual con algunos formatos
+0

Las herramientas de línea de comandos son feas de invocar desde Java (en mi caso, JUnit). –

8

Considere la posibilidad de utilizar mi proyecto simple-excel que proporciona un montón de jamón cresta Matchers para hacer el trabajo.

Cuando haces algo como lo siguiente,

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

Veías, por ejemplo,

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) 

De esta manera, se puede ejecutar desde sus pruebas automatted y obtener una retroalimentación significativa mientras estás desarrollando

Usted puede leer más sobre él en this article on my site

+0

Si usted es el desarrollador de este proyecto, probablemente debería agregar un descargo a tal efecto. –

+0

no estoy seguro de por qué es importante, es un proyecto de OSS ... – Toby

+0

Porque además de ser una buena forma, es una regla de este sitio, consulte http://stackoverflow.com/faq#promotion. –

4

que tenía que hacer algo similar y ya estaba usando el Apache POI library en mi proyecto para crear archivos de Excel. Así que opté por utilizar la interfaz incluida ExcelExtractor para exportar ambos libros como una cadena de texto y afirmé que las cadenas eran iguales. Hay implementaciones tanto para HSSF for .xls como para XSSF for .xlsx.

volcado a cadena:

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

ExcelExtractor tiene algunas opciones para todo lo que se debe incluir en el vertedero de cadena. Descubrí que tiene valores predeterminados útiles para incluir nombres de hoja. Además, incluye los contenidos de texto de las celdas.

2

La manera más fácil que encuentro es usar Tika. lo uso como esto:

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

Se ve bien, yo ¡Probablemente usaría esto la próxima vez! –

Cuestiones relacionadas