Issue
I have an API where file are placed in some distinct directory, and file names are made up of fixed prefix/postfix parts. I want to abstract away those parts, so that users of my helper class can focus on what needs to be done.
Example code:
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));
}
As you can see, it is possible to fully test getFilePath()
and deleteFileIfExists()
. But is there a meaningful way to test the one API deleteFileIfExistsUsing(String)
?
The only option I see: have another class that provides the Path-based calls, and then give the FileManager
an instance of that class ... that could then be mocked. But that feels a bit like overkill.
So: are the other ways to test the public method from FileManager
?
( side note: one goal is that the unit test is somehow platform independent. The above actually works on Linux and Windows for example )
Solution
Inject a Function<String, Path>
into the constructor of FileManager
:
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");
}
// ...
}
Then you can inject Paths::get
in production code, and something that, say, returns mock Path
s in tests.
Answered By - Andy Turner