Comparer des fichiers texte avec Junit
je compare des fichiers texte en junit en utilisant:
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());
}
Est-ce une bonne façon de comparer des fichiers texte? Ce qui est préférable?
9 réponses
junit-addons a beau soutien pour elle: FileAssert
il vous donne des exceptions comme:
junitx.framework.ComparisonFailure: aa Line [3] expected: [b] but was:[a]
Voici une approche simple pour vérifier si les fichiers sont exactement le même:
assertEquals("The files differ!",
FileUtils.readFileToString(file1, "utf-8"),
FileUtils.readFileToString(file2, "utf-8"));
où file1
et file2
sont File
instances, et FileUtils
est de Apache Commons IO .
pas beaucoup de propre code à maintenir pour vous, ce qui est toujours un plus. :) Et très facile si vous utilisez déjà Apache Commons dans votre projet. Mais pas de bons messages d'erreur détaillés comme dans mark's solution .
Modifier :
Heh, en regardant de plus près à la FileUtils
API, il y a un pair voie plus simple :
assertTrue("The files differ!", FileUtils.contentEquals(file1, file2));
en bonus, cette version Fonctionne pour tous les fichiers, pas seulement le texte.
Voici une liste plus exhaustive de comparateurs de fichiers dans diverses bibliothèques Java tierces:
à partir de 2015, je recomenterais AssertJ , une bibliothèque d'assertions élégante et complète. Pour les fichiers, vous pouvez affirmer contre un autre fichier:
@Test
public void file() {
File actualFile = new File("actual.txt");
File expectedFile = new File("expected.txt");
assertThat(actualFile).hasSameContentAs(expectedFile);
}
ou contre inline chaînes:
@Test
public void inline() {
File actualFile = new File("actual.txt");
assertThat(linesOf(actualFile)).containsExactly(
"foo 1",
"foo 2",
"foo 3"
);
}
les messages de défaillance sont également très informatifs. Si une ligne est différente, vous obtenez:
java.lang.AssertionError:
File:
<actual.txt>
and file:
<expected.txt>
do not have equal content:
line:<2>,
Expected :foo 2
Actual :foo 20
et si l'un des fichiers a plus de lignes vous obtenez:
java.lang.AssertionError:
File:
<actual.txt>
and file:
<expected.txt>
do not have equal content:
line:<4>,
Expected :EOF
Actual :foo 4
je suggère D'utiliser Assert.assertThat et un hamcrest matcher (junit 4.5 ou plus tard - peut-être même 4.4).
je finirais avec quelque chose comme:
assertThat(fileUnderTest, containsExactText(expectedFile));
où mon matcher est:
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;
}
}
}
}
Matcher pour:
- Composition et réutilisation
- utiliser en code normal ainsi qu'en test
- Collections
- utilisé dans le(S) cadre (s) simulé (s)
- peut être utilisé une fonction générale de prédicat
- Vraiment sympa journal-capacité
- peut être combiné avec d'autres assemblages et les descriptions et descriptions des défaillances sont exactes et précises
Inconvénients:
- Eh bien, c'est assez évident, non? C'est beaucoup plus verbeux que assert ou junitx (pour ce cas particulier)
- vous aurez probablement besoin d'inclure les libs hamcrest pour obtenir le plus d'avantages
FileUtils
c'est une bonne idée. Voici encore un autre approche simple pour vérifier si les fichiers sont exactement les mêmes.
assertEquals(FileUtils.checksumCRC32(file1), FileUtils.checksumCRC32(file2));
alors que les assertEquals() fournissent un peu plus de feedback que l'assertTrue(), le résultat de checksumCRC32() est long. Oui, c'est peut-être pas intrinsèquement utile.
simple comparaison du contenu de deux fichiers avec java.nio.fichier API.
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);
ou si vous voulez comparer les lignes individuelles:
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));
}
si prévu a plus de lignes que réel, vous échouerez une assertEquals avant d'arriver à l'assertNull plus tard.
il est assez facile de fixer cependant:
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());
}
C'est ma propre implémentation de equalFiles
, pas besoin d'ajouter de bibliothèque à votre projet.
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;
}
et pour l'utiliser il suffit d'utiliser régulier AssertTrue
méthode de JUnit
assertTrue(equalFiles(expected, output)) ;