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é?
junit-addons a un support Nice pour cela: 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 identiques:
assertEquals("The files differ!",
FileUtils.readFileToString(file1, "utf-8"),
FileUtils.readFileToString(file2, "utf-8"));
Où file1
et file2
sont des instances File
et où FileUtils
provient de Apache Commons IO .
Pas beaucoup de code à gérer pour vous, ce qui est toujours un avantage. :) Et très facile si vous utilisez déjà Apache Commons dans votre projet. Mais pas de Nice, des messages d'erreur détaillés comme dans la solution de mark .
Modifier:
Heh, en regardant de plus près l'API FileUtils
, il y a un même 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:
À compter de 2015, je recommanderais 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 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 instructifs. 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érerais d'utiliser Assert.assertThat et un hamcrest matcher (junit 4.5 ou version ultérieure - peut-être même 4,4).
Je finirais avec quelque chose comme:
assertThat(fileUnderTest, containsExactText(expectedFile));
où est 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:
Les inconvénients:
FileUtils
sûr est un bon. Voici encore une autre approche simple pour vérifier si les fichiers sont exactement les mêmes.
assertEquals(FileUtils.checksumCRC32(file1), FileUtils.checksumCRC32(file2));
AssertEquals () fournit un peu plus de retour que l'assertTrue (), mais le résultat de checksumCRC32 () est long. Donc, cela peut ne pas être intrisiquement utile.
Comparaison simple 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 prévu contient plus de lignes que réel, vous échouerez avec assertEquals avant d’obtenir l'assertNull ultérieurement.
C'est assez facile à résoudre 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());
}
Ceci est ma propre implémentation de equalFiles
, inutile 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 la méthode AssertTrue
JUnit régulière
assertTrue(equalFiles(expected, output)) ;