You seem to be after contradictory goals. On the one hand, you’re trying to avoid writing data to disk, which isn’t a bad goal in tests. On the other, you’re trying to test your I/O-handling class, which means you’ll be working with system utilities that assume that your File
will work with native calls. As such, here’s my guidance:
- Don’t try to mock a
File
. Just don’t. Too many native things depend on it. - If you can, split your I/O-handling code into the half that opens a
File
and turns it into aReader
, and the half that parses HTML out of theReader
. - At that point, you don’t need a mock at all–just construct a
StringReader
to simulate the data source. - While that handles your unit tests pretty well, you may also want to write an integration test that uses a temporary file and ensure that it reads right. (Thanks Brice for adding that tip!)
Don’t be afraid to refactor your class to make testing easier, as here:
class YourClass {
public int method(File file) {
// do everything here, which is why it requires a mock
}
}
class YourRefactoredClass {
public int method(File file) {
return methodForTest(file.getName(), file.isFile(),
file.isAbsolute(), new FileReader(file));
}
/** For testing only. */
int methodForTest(
String name, boolean isFile, boolean isAbsolute, Reader fileContents) {
// actually do the calculation here
}
}
class YourTest {
@Test public int methodShouldParseBadHtml() {
YourRefactoredClass yrc = new YourRefactoredClass();
assertEquals(42, yrc.methodForTest(
"bad.html", true, false, new StringReader(badHTMLText));
}
}
At this point the logic in method
is so straightforward it’s not worth testing,
and the logic in methodForTest
is so easy to access that you can test it heavily.