简体   繁体   English

将文本文件与 Junit 进行比较

[英]Comparing text files with Junit

I am comparing text files in junit using:我正在使用以下方法比较 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());
}

Is this a good way to compare text files?这是比较文本文件的好方法吗? What is preferred?什么是首选?

Here's one simple approach for checking if the files are exactly the same:这是检查文件是否完全相同的一种简单方法:

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

Where file1 and file2 are File instances, and FileUtils is from Apache Commons IO .其中file1file2File实例, FileUtils来自Apache Commons IO

Not much own code for you to maintain, which is always a plus.没有多少自己的代码需要你维护,这总是一个加分项。 :) And very easy if you already happen to use Apache Commons in your project. :) 如果您已经在您的项目中使用了 Apache Commons,则非常容易。 But no nice, detailed error messages like in mark's solution .但是没有像mark 的解决方案那样好的、详细的错误消息。

Edit :编辑
Heh, looking closer at the FileUtils API, there's an even simpler way :呵呵,仔细看看FileUtils API,还有一种更简单的方法

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

As a bonus, this version works for all files, not just text.作为奖励,此版本适用于所有文件,而不仅仅是文本。

junit-addons has nice support for it: FileAssert junit-addons对它有很好的支持: FileAssert

It gives you exceptions like:它为您提供以下例外情况:

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

As of 2015, I would recomment AssertJ , an elegant and comprehensive assertion library.到 2015 年为止,我会推荐AssertJ ,这是一个优雅而全面的断言库。 For files, you can assert against another file:对于文件,您可以针对另一个文件进行断言:

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

or against inline strings:或针对内联字符串:

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

The failure messages are very informative as well.失败消息也非常有用。 If a line is different, you get:如果一行不同,你会得到:

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

and if one of the files has more lines you get:如果其中一个文件有更多行,您会得到:

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

Simple comparison of the content of two files with java.nio.file API.java.nio.file 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);

Or if you want to compare individual lines:或者,如果您想比较各个行:

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));
}

I'd suggest using Assert.assertThat and a hamcrest matcher (junit 4.5 or later - perhaps even 4.4).我建议使用 Assert.assertThat 和hamcrest 匹配器(junit 4.5 或更高版本 - 甚至可能是 4.4)。

I'd end up with something like:我最终会得到类似的东西:

assertThat(fileUnderTest, containsExactText(expectedFile));

where my matcher is:我的匹配器在哪里:

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 and reuse组合和重用
  • Use in normal code as well as test在普通代码和测试中使用
    • Collections收藏
    • Used in mock framework(s)在模拟框架中使用
    • Can be used a general predicate function可以使用一般谓词函数
  • Really nice log-ability非常好的日志能力
  • Can be combined with other matchers and descriptions and failure descriptions are accurate and precise可与其他匹配器结合,描述和故障描述准确准确

Cons:缺点:

  • Well it's pretty obvious right?嗯,这很明显吧? This is way more verbose than assert or junitx (for this particular case)这比 assert 或 junitx 更冗长(对于这种特殊情况)
  • You'll probably need to include the hamcrest libs to get the most benefit您可能需要包含 hamcrest 库才能获得最大收益

FileUtils sure is a good one. FileUtils肯定是一个不错的选择。 Here's yet another simple approach for checking if the files are exactly the same.这是检查文件是否完全相同的另一种简单方法

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

While the assertEquals() does provide a little more feedback than the assertTrue(), the result of checksumCRC32() is a long.虽然 assertEquals() 确实比 assertTrue() 提供了更多的反馈,但 checksumCRC32() 的结果很长。 So, that may not be intrisically helpful.所以,这可能没有内在的帮助。

If expected has more lines than actual, you'll fail an assertEquals before getting to the assertNull later.如果预期的行数多于实际行数,则在稍后到达 assertNull 之前,您将失败 assertEquals。

It's fairly easy to fix though:不过修复起来相当容易:

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());
}

This is my own implementation of equalFiles , no need to add any library to your project.这是我自己的equalFiles实现,无需向您的项目添加任何库。

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;

}

And to use it just use regular AssertTrue JUnit method并使用它只需使用常规的AssertTrue JUnit 方法

assertTrue(equalFiles(expected, output)) ;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM