无法让 JUnit 测试失败(它应该)

Can't get JUnit test to fail (it should)

我在一个JUnit测试中有如下代码(只包含相关部分)

private String testRoot = System.getProperty("user.home");
private String destFail2 = testRoot + "/GoogleDrive/TestFail//..\...//*";

@Test
public void given_NamedParameterizedFileSet_when_SavedWithInvalidFileName_then_Exception() {
    String invalidFullPathToFileSet = fsPathDir + invalidBackupName;
    //test save fully parameterized empty file set at non-existent directory
    try {
        FileSet fs = new FileSet(backupName, dest);
        try {
            FileSet.save(invalidFullPathToFileSet, fs);
            fail("Save name is invalid, should refuse save");
        } catch (IOException e) {
            assert(true);
        }
    } catch (Exception e1) {
        e1.printStackTrace();
        fail("Could not create the file set");
    }
}

FileSet.save()的代码如下:

public static void save(String fullPathToFile, FileSet fileSet) throws IOException {
    ObjectOutputStream out = null;
    Path outFilePath = Paths.get(fullPathToFile);
    Path outDirPath = outFilePath.getParent();

    if (Files.exists(outFilePath)) {
        Files.delete(outFilePath);
    }
    if (!Files.exists(outDirPath)) {
        Files.createDirectories(outDirPath);
    }
    try {
        out = new ObjectOutputStream(new
                BufferedOutputStream(Files.newOutputStream(outFilePath)));
        out.writeObject(fileSet);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        out.close();
    }
}

上面的 FileSet.save() 方法应该失败,因为它被赋予我 认为 是一个无效的文件名,但不知何故代码运行得很好而没有抛出异常(在 Mac 上;还没有在 Windows 上尝试过)。

  1. 为什么代码是运行?
  2. 根据代码,我在哪里可以找到它创建的文件?
  3. 我需要什么样的文件名 "bad?" 我尝试创建一个带有冒号 (:) 的文件名,因为它应该是 Mac 上唯一的非法字符,但即使行得通,它最终创建了一个名称中间有冒号的文件...
  4. 是否有 "better" 方式来编写 FileSet.save()(而不是使用 Path,我应该使用 File 并将路径作为字符串传递给构造函数)?

异常处理不当,测试成功。在内部 try-catch:

try {
  FileSet.save(invalidFullPathToFileSet, fs);
  fail("Save name is invalid, should refuse save");
} catch (IOException e) {
  assert(true);
}

FileSet.save(invalidFullPathToFileSet, fs); 抛出异常,因此下一行本应未通过测试,但未执行,执行流程被重定向到 catch 块,您只需 assert(true)(这是单元测试中完全无用的语句),然后退出内部和外部 try-catch 块,导致成功执行。

你应该做的是:

try {
  FileSet.save(invalidFullPathToFileSet, fs);
} catch (IOException e) {
  e.printStackTrace();
  fail("Save name is invalid, should refuse save");
}

只要抛出异常,测试就会失败。

首先,不要使用 assert 关键字 - 如果您 运行 没有 -ea 参数的 java 应用程序 ("enable assertions"),此行将根本不执行。顺便说一句 assert true 什么都不做。

其次,你不关心的异常,那些你没有测试的,比如e1不应该被捕获,声明测试方法抛出它。它将减少不必要的复杂性。

最后,我建议使用 ExpectedException 来做这个断言:

@Rule
public final ExpectedException expectedException = ExpectedException.none();

@Test
public void given_NamedParameterizedFileSet_when_SavedWithInvalidFileName_then_Exception() throws Exception {
    String invalidFullPathToFileSet = fsPathDir + invalidBackupName;
    FileSet fs = new FileSet(backupName, dest);

    expectedException.expect(IOException.class);

    FileSet.save(invalidFullPathToFileSet, fs);
}

这样您还可以查看消息。它还检查异常是否在 expect 行之后抛出。所以如果 new FileSet(...) 抛出 IOException,测试就会失败。注意,ExpectedException 需要注释为 @Rule 让 junit 现在在测试结束时执行检查。