2

Is there a nice way to test code which performs IO? In Java in particular, if you go the Mock route, you need to wrap most of the native APIs in your own mockable classes, something like:

public class Filesystem {
  public void write(String filename, String text) throws FileNotFoundException {
    try (PrintWriter out = new PrintWriter(filename)) {
      out.println(text);
    }
  }
}

and then pass in an instance of Filesystem to any class that needs to write text for a file. Is there a better way?

5
  • 2
    Do you trust the file system? How much of your budget is dedicated to testing the operating system, vs testing your code? Memory streams can replace file streams in most languages, so there is no need to mock a file system. Sep 29, 2017 at 21:39
  • 2
    @FrankHileman: the first part of your comment does not quite fit. OP is not talking about testing the file system, they talk about testing by isolating from the file system. The second part about using memory streams, however, could be part of a good answer.
    – Doc Brown
    Sep 29, 2017 at 22:19
  • 1
    @DocBrown yes, I understand, and interacting with the file system, without a dedicated directory per test run, can be fragile. But you isolate from the file system because you don't trust the file system. Otherwise, you could simply use the file system, check for the presence of files, etc. Sep 29, 2017 at 22:21
  • 1
    @FrankHileman: there can be more reasons to isolate from the file sytem in "real" unit tests than just distrust. However, I agree, not to mock file system calls at all can be indeed a sensible approach for lots of situations. So why not put this into an answer?
    – Doc Brown
    Sep 29, 2017 at 22:29
  • @DocBrown Thanks, but, I don't think I addressed the question directly. More like an alternative. Sep 29, 2017 at 23:12

1 Answer 1

4

Just like Frank says in the comment, I don't believe there is need to stub out file system.

Stubs exist because service you call is :

  • Too complicated, that your test would mostly be testing that than
  • Can change often, making your tests unstable
  • Calling it might fail, making your test fragile
  • Too slow to call, making your whole test suite slow
  • The service might persist data that we send it, and make it hard to remove it

File system is none of those. Trying to stub it out would mean you implement exactly same features, only in-memory. It is extremely stable, so you don't have to worry about it changing. Calling file system rarely fails. File system operations are relatively fast. And while file system is persistent, it is easy to wipe it before every test.

So as long as you keep proper separation between tests, it is perfectly fine to use file system. This can be achieved, for example, by appending test name to each file/folder used by the test.

3
  • You missed a reason to stub, which can apply to the file system: The service persists data in a way that parallel executed tests interfere with each other. Oct 1, 2017 at 7:44
  • @BartvanIngenSchenau Nope. Read the last paragraph.
    – Euphoric
    Oct 1, 2017 at 8:41
  • If the code is structured such that it uses a root directory and relative directory paths appended to that, the root directory can be unique per test, passed in as a parameter. This is one way to avoid the interaction between tests. Oct 2, 2017 at 22:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.