Comparer des fichiers texte avec Junit
-
19-08-2019 - |
Question
Je compare des fichiers texte dans 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 un bon moyen de comparer des fichiers texte? Qu'est-ce qui est préféré?
La solution
junit-addons est très bien supporté: FileAssert
Cela vous donne des exceptions telles que:
junitx.framework.ComparisonFailure: aa Line [3] expected: [b] but was:[a]
Autres conseils
Voici une approche simple pour vérifier si les fichiers sont exactement identiques:
assertEquals("The files differ!",
FileUtils.readFileToString(file1, "utf-8"),
FileUtils.readFileToString(file2, "utf-8"));
Où fichier1
et fichier2
sont des instances Fichier
et FileUtils
provient de Apache Commons IO .
Peu de code personnel à gérer, ce qui est toujours un avantage. :) Et très facile si vous utilisez déjà Apache Commons dans votre projet. Mais pas de messages d'erreur détaillés comme dans la solution de la marque .
Modifier :
En regardant de plus près l’API FileUtils
, il existe même un moyen plus simple :
assertTrue("The files differ!", FileUtils.contentEquals(file1, file2));
En prime, cette version fonctionne pour tous les fichiers, pas seulement le texte.
Voici une liste plus exhaustive des comparateurs de fichiers dans diverses bibliothèques Java tierces:
À partir de 2015, je recommanderais AssertJ , une affirmation élégante et complète bibliothèque. 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 des chaînes en ligne:
@Test
public void inline() {
File actualFile = new File("actual.txt");
assertThat(linesOf(actualFile)).containsExactly(
"foo 1",
"foo 2",
"foo 3"
);
}
Les messages d'échec 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 contient plusieurs 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érerais d'utiliser Assert.assertThat et un hamcrest matcher (Junit version 4.5 ou ultérieure). - peut-être même 4,4).
Je finirais avec quelque chose comme:
assertThat(fileUnderTest, containsExactText(expectedFile));
où se trouve mon matcher:
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 pros:
- Composition et réutilisation
- Utiliser dans le code normal ainsi que dans les tests
- Collections
- Utilisé dans un ou plusieurs cadres
- Peut être utilisée comme fonction de prédicat général
- Très belle capacité de journalisation
- Peut être combiné avec d'autres correspondants et les descriptions et les descriptions d'échec sont précises
Inconvénients:
- C'est assez évident non? C'est beaucoup plus verbeux que l'assert ou junitx (pour ce cas particulier)
- Vous aurez probablement besoin d'inclure les bibliothèques hamcrest pour obtenir le plus d'avantages
FileUtils
est certainement bon. Voici encore un autre approche simple pour vérifier si les fichiers sont exactement les mêmes.
assertEquals(FileUtils.checksumCRC32(file1), FileUtils.checksumCRC32(file2));
Bien que l'assertEquals () fournisse un peu plus de retour que l'assertTrue (), le résultat de checksumCRC32 () est long. Donc, cela pourrait ne pas être très utile.
Comparaison Simpel du contenu de deux fichiers avec l'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);
Ou si vous souhaitez comparer des 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 vous avez prévu plus de lignes que de résultats, vous échouerez avec assertEquals avant de passer à assertNull plus tard.
Il est assez facile de résoudre ce problème:
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());
}
Ceci est ma propre implémentation de equalFiles
, inutile d'ajouter une 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 la méthode AssertTrue
JUnit classique
assertTrue(equalFiles(expected, output)) ;