2009-01-21 33 views
36

estoy comparando archivos de texto en junit usando:comparar archivos de texto con Junit

public static void assertReaders(BufferedReader expected, 
      BufferedReader actual) throws IOException { 
    String line; 
    while ((line = expected.readLine()) != null) { 
     assertEquals(line, actual.readLine()); 
    } 

    assertNull("Actual had more lines then the expected.", actual.readLine()); 
    assertNull("Expected had more lines then the actual.", expected.readLine()); 
} 

¿Es esta una buena manera de comparar archivos de texto? ¿Qué se prefiere?

Respuesta

31

junit-addons tiene buen soporte para el mismo: FileAssert

Le da excepciones como:

junitx.framework.ComparisonFailure: aa Line [3] expected: [b] but was:[a] 
+1

Solo una nota la última versión vin maven central repo es de 2003 y la versión 1.4, así que no sé si es compatible con las últimas versiones. – kohlerfc

4

Si se espera que tenga más líneas que las reales, fallará una assertEquals antes de llegar a la assertNull más tarde.

Es bastante fácil de solucionar sin embargo:

public static void assertReaders(BufferedReader expected, 
    BufferedReader actual) throws IOException { 
    String expectedLine; 
    while ((expectedLine = expected.readLine()) != null) { 
    String actualLine = actual.readLine(); 
    assertNotNull("Expected had more lines then the actual.", actualLine); 
    assertEquals(expectedLine, actualLine); 
    } 
    assertNull("Actual had more lines then the expected.", actual.readLine()); 
} 
+0

me gusta que su respuesta no se basa en ninguna biblioteca de terceros, pero este código no se compilará.El alcance de la variable 'real' está limitado al ciclo while, por lo que la línea final assertNull no se compilará. – buzz3791

+0

@ buzz3791: No, el alcance de 'actualLine' está limitado al ciclo while. El alcance de 'real' es todo el método. –

+0

Vaya, gracias por señalar mi error. – buzz3791

7

me gustaría sugerir el uso de aserción. assertThat y un hamcrest matcher (junit 4.5 o posterior - quizás incluso 4.4).

que iba a terminar con algo como:

assertThat(fileUnderTest, containsExactText(expectedFile)); 

donde mi matcher es:

class FileMatcher { 
    static Matcher<File> containsExactText(File expectedFile){ 
     return new TypeSafeMatcher<File>(){ 
     String failure; 
     public boolean matchesSafely(File underTest){ 
      //create readers for each/convert to strings 
      //Your implementation here, something like: 
       String line; 
       while ((line = expected.readLine()) != null) { 
       Matcher<?> equalsMatcher = CoreMatchers.equalTo(line); 
       String actualLine = actual.readLine(); 
       if (!equalsMatcher.matches(actualLine){ 
        failure = equalsMatcher.describeFailure(actualLine); 
        return false; 
       } 
       } 
       //record failures for uneven lines 
     } 

     public String describeFailure(File underTest); 
      return failure; 
     } 
     } 
    } 
} 

pros Matcher:

  • Composición y reutilizar
  • uso en condiciones normales código y prueba
    • Colecciones
    • utilizadas en las armaduras (s) maqueta
    • Se puede utilizar una función de predicado en general
  • muy bonito log-capacidad
  • se puede combinar con otros comparadores y las descripciones y las descripciones de fallo son exactos y precisos

Contras:

  • Bueno, es bastante obvio ¿verdad? Esta es la forma más prolija que afirmar o junitx (para este caso particular)
  • Usted va a necesitar para incluir las librerías hamcrest a obtener el mayor beneficio
36

He aquí un método sencillo para comprobar si los archivos son exactamente el mismo:

assertEquals("The files differ!", 
    FileUtils.readFileToString(file1, "utf-8"), 
    FileUtils.readFileToString(file2, "utf-8")); 

Dónde file1 y file2 son File casos, y es a partir FileUtilsApache Commons IO.

No hay mucho código propio para mantener, que siempre es un plus. :) Y es muy fácil si ya utilizas Apache Commons en tu proyecto. Pero no hay mensajes de error agradables y detallados como en mark's solution.

Editar:
Je, mirando más de cerca a la API FileUtils, hay una aún simpler way:

assertTrue("The files differ!", FileUtils.contentEquals(file1, file2)); 

Como beneficio adicional, esta versión funciona para todos los archivos, no sólo texto.

+2

La forma assertTrue es concisa, pero relativamente inútil cuando falla. Al menos, el método assertEquals le mostrará algunos caracteres en los que son diferentes – Stephen

+3

** Actualización **: hoy recomendaría [Google Guava] (http://code.google.com/p/guava-libraries/) durante Commons IO para leer los archivos como una cadena: 'Files.toString (file1, Charset.forName (" UTF-8 "));' No hay mucha diferencia en un caso como este, pero en general, la guayaba es más limpia, está mejor documentada y una biblioteca mantenida activamente. – Jonik

+1

Y como ** Java 7 ** puede [leer un archivo de texto como una cadena] (http://stackoverflow.com/a/326440/56285) simplemente sin ninguna libreta externa: 'new String (Files.readAllBytes (Paths.get ("/ ruta/a/archivo.txt")), StandardCharsets.UTF_8) ' – Jonik

5

FileUtils seguro es una buena. Aquí hay otra simple approach para verificar si los archivos son exactamente iguales.

assertEquals(FileUtils.checksumCRC32(file1), FileUtils.checksumCRC32(file2)); 

Mientras que los assertEquals() proporciona un poco más de retroalimentación que el assertTrue(), el resultado de checksumCRC32() es mucho. Entonces, eso puede no ser intrínsicamente útil.

+1

+1, supongo que esto podría ser útil para archivos realmente grandes (cuando solo te importa si los archivos son diferentes, no cuál es la diferencia) – Jonik

11

A partir de 2015, Lo recomiendo AssertJ, una elegante y completa biblioteca de afirmación. Para los archivos, puede oponer otro archivo:

@Test 
public void file() { 
    File actualFile = new File("actual.txt"); 
    File expectedFile = new File("expected.txt"); 
    assertThat(actualFile).hasSameContentAs(expectedFile); 
} 

o contra las cuerdas en línea:

@Test 
public void inline() { 
    File actualFile = new File("actual.txt"); 
    assertThat(linesOf(actualFile)).containsExactly(
      "foo 1", 
      "foo 2", 
      "foo 3" 
    ); 
} 

Los mensajes de error son muy informativo también. Si una línea es diferente, se obtiene:

java.lang.AssertionError: 
File: 
    <actual.txt> 
and file: 
    <expected.txt> 
do not have equal content: 
line:<2>, 
Expected :foo 2 
Actual :foo 20 

y si uno de los archivos tiene más líneas que se obtiene:

java.lang.AssertionError: 
File: 
    <actual.txt> 
and file: 
    <expected.txt> 
do not have equal content: 
line:<4>, 
Expected :EOF 
Actual :foo 4 
+0

El método 'hasContentEqualTo' es desaprobado a partir de este comentario. Use 'hasSameContentAs' en su lugar. – Stephan

+0

Gracias por señalarlo, he actualizado la respuesta. –

0

Ésta es mi propia implementación de equalFiles, sin necesidad de añadir ningún biblioteca para tu proyecto.

private static boolean equalFiles(String expectedFileName, 
     String resultFileName) { 
    boolean equal; 
    BufferedReader bExp; 
    BufferedReader bRes; 
    String expLine ; 
    String resLine ; 

    equal = false; 
    bExp = null ; 
    bRes = null ; 

    try { 
     bExp = new BufferedReader(new FileReader(expectedFileName)); 
     bRes = new BufferedReader(new FileReader(resultFileName)); 

     if ((bExp != null) && (bRes != null)) { 
      expLine = bExp.readLine() ; 
      resLine = bRes.readLine() ; 

      equal = ((expLine == null) && (resLine == null)) || ((expLine != null) && expLine.equals(resLine)) ; 

      while(equal && expLine != null) 
      { 
       expLine = bExp.readLine() ; 
       resLine = bRes.readLine() ; 
       equal = expLine.equals(resLine) ; 
      } 
     } 
    } catch (Exception e) { 

    } finally { 
     try { 
      if (bExp != null) { 
       bExp.close(); 
      } 
      if (bRes != null) { 
       bRes.close(); 
      } 
     } catch (Exception e) { 
     } 

    } 

    return equal; 

} 

Y para usarlo solo uso regular método AssertTrue JUnit

assertTrue(equalFiles(expected, output)) ; 
4

comparación Simpel del contenido de dos archivos con API java.nio.file.

byte[] file1Bytes = Files.readAllBytes(Paths.get("Path to File 1")); 
byte[] file2Bytes = Files.readAllBytes(Paths.get("Path to File 2")); 

String file1 = new String(file1Bytes, StandardCharsets.UTF_8); 
String file2 = new String(file2Bytes, StandardCharsets.UTF_8); 

assertEquals("The content in the strings should match", file1, file2); 

O si desea comparar las líneas individuales:

List<String> file1 = Files.readAllLines(Paths.get("Path to File 1")); 
List<String> file2 = Files.readAllLines(Paths.get("Path to File 2")); 

assertEquals(file1.size(), file2.size()); 

for(int i = 0; i < file1.size(); i++) { 
    System.out.println("Comparing line: " + i) 
    assertEquals(file1.get(i), file2.get(i)); 
} 
Cuestiones relacionadas