如何正确地对 "abstracted" 文件处理进行单元测试?
How to properly unit test "abstracted" file handling?
我有一个 API 文件放置在某个不同的目录中,文件名由固定的 prefix/postfix 部分组成。我想抽象出这些部分,以便我的助手 class 的用户可以专注于需要完成的事情。
示例代码:
static class FileManager {
Path getFilePath(String arg) {
return Paths.get("/whatever", "prefix_" + arg + "_postfix");
}
void deleteFileIfExists(Path path) {
if (path.toFile().exists())
path.toFile().delete();
}
public void deleteFileIfExistsUsing(String arg) {
deleteFileIfExists(getFilePath(arg));
}
}
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void testGetFilePath() {
assertThat(new FileManager().getFilePath("bar"), is(Paths.get("/whatever/prefix_bar_postfix")));
}
@Test
public void testDelete() throws IOException {
File subfolder = temporaryFolder.newFolder("whatever");
File fileToDelete = new File(subfolder, "prefix_bar_postfix");
fileToDelete.createNewFile();
assertThat(fileToDelete.exists(), is(true));
new FileManager().deleteFileIfExists(fileToDelete.toPath());
assertThat(fileToDelete.exists(), is(false));
}
如您所见,可以完全测试 getFilePath()
和 deleteFileIfExists()
。但是有没有一种有意义的方法来测试 API deleteFileIfExistsUsing(String)
?
我看到的唯一选择:让 另一个 class 提供基于路径的调用,然后给 FileManager
那个 class ...然后可以嘲笑。但这感觉有点矫枉过正。
那么:还有其他方法可以测试 FileManager
中的 public 方法吗?
(旁注:一个目标是单元测试在某种程度上是独立于平台的。以上实际上适用于 Linux 和 Windows 例如)
您应该模拟 path.toFile().exists()
以获得两个单元测试,一个模拟现有文件,一个模拟不存在的文件。
Stack
上的 mockito 示例
在FileManager
的构造函数中注入一个Function<String, Path>
:
static class FileManager {
private final Function<String, Path> pathFactory;
FileManager(Function<String, Path> pathFactory) {
this.pathFactory = pathFactory;
}
Path getFilePath(String arg) {
return pathFactory.apply("/whatever/prefix_" + arg + "_postfix");
}
// ...
}
然后您可以在生产代码中注入 Paths::get
,然后在测试中注入 returns 模拟 Path
的东西。
我有一个 API 文件放置在某个不同的目录中,文件名由固定的 prefix/postfix 部分组成。我想抽象出这些部分,以便我的助手 class 的用户可以专注于需要完成的事情。
示例代码:
static class FileManager {
Path getFilePath(String arg) {
return Paths.get("/whatever", "prefix_" + arg + "_postfix");
}
void deleteFileIfExists(Path path) {
if (path.toFile().exists())
path.toFile().delete();
}
public void deleteFileIfExistsUsing(String arg) {
deleteFileIfExists(getFilePath(arg));
}
}
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Test
public void testGetFilePath() {
assertThat(new FileManager().getFilePath("bar"), is(Paths.get("/whatever/prefix_bar_postfix")));
}
@Test
public void testDelete() throws IOException {
File subfolder = temporaryFolder.newFolder("whatever");
File fileToDelete = new File(subfolder, "prefix_bar_postfix");
fileToDelete.createNewFile();
assertThat(fileToDelete.exists(), is(true));
new FileManager().deleteFileIfExists(fileToDelete.toPath());
assertThat(fileToDelete.exists(), is(false));
}
如您所见,可以完全测试 getFilePath()
和 deleteFileIfExists()
。但是有没有一种有意义的方法来测试 API deleteFileIfExistsUsing(String)
?
我看到的唯一选择:让 另一个 class 提供基于路径的调用,然后给 FileManager
那个 class ...然后可以嘲笑。但这感觉有点矫枉过正。
那么:还有其他方法可以测试 FileManager
中的 public 方法吗?
(旁注:一个目标是单元测试在某种程度上是独立于平台的。以上实际上适用于 Linux 和 Windows 例如)
您应该模拟 path.toFile().exists()
以获得两个单元测试,一个模拟现有文件,一个模拟不存在的文件。
Stack
在FileManager
的构造函数中注入一个Function<String, Path>
:
static class FileManager {
private final Function<String, Path> pathFactory;
FileManager(Function<String, Path> pathFactory) {
this.pathFactory = pathFactory;
}
Path getFilePath(String arg) {
return pathFactory.apply("/whatever/prefix_" + arg + "_postfix");
}
// ...
}
然后您可以在生产代码中注入 Paths::get
,然后在测试中注入 returns 模拟 Path
的东西。