How to Mock a FileInputStream/ <any>Stream in Java?

llllzllll
3 min readOct 10, 2019

TL;DR: When you are having questions like this. It’s very likely that you are not following Dependency Inversion Principle closely. And my StackOverflow answer is shorter too :

We all know that Stream is good. It removes the overhead of reading files by not loading all the file content to our memory. But what if you have to mock one of your stream one point in your life? I had to when I was working with some legacy code in our code base. And I needed to add unit test to a place where I need to mock a FileInputStream. I scratched my head, because the only way to construct a FileInputStream is to pass in a file, but no one wants to have input files for unit tests. It will immediately integrate your unit test with your file system, which will not be a unit test anymore. Or I could mock the read method of the stream, but that’s a lot of work, too.

At this point, you may have realized that you are struggling a lot because those are just specific implementation detail of FileInputStream. Also the code is too coupled with the FileInputStream implementation that we can’t use other stream implementation anymore. So it’s the best practice to use the interface/ abstract class of FileInputStream instead of using the concrete class, which is exactly what’s dictated by dependency inversion principle. Let’s have

By design, each stream provided by Java util package has it’s own purpose. If you want to just pass a string or byte array to the stream, then you need to use ByteArrayInputStream instead.

Let’s read how the principle is defined in the Wiki page:

1. High-level modules should not depend on low-level modules. Both should depend on abstractions (e.g. interfaces).

2. Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.

In this case, FileInputStream is the low level module, it has very specific implementation detail and we don’t want any of our own interface to be coupled with this implementation. And of course, this implementation depends on its own abstraction — InputStream. Conclusion: our code should depend on InputStream instead of FileInputStream.

Given you have the following adapter for FileInputStream

class FileReader {
public InputStream readAsStream() {
return new FileInputStream("path/to/File.txt");
}
}

You can then easily mock it to return ByteArrayInputStream instead, because it simply takes a byte stream as the input. That’s almost the simplest data you could get in Java! (mockito code below):

FileReader fd = mock(FileReader());
String fileContent = ...;
ByteArrayInputStream bais = new ByteArrayInputStream(fileContent);
when(fd.readAsStream()).thenReturn(bais);

The takeaway here is: when you are using a reaonably designed package, there should be an interface corresponding to the specific implementation you want to use. Use the abstraction by all means!

Also we should also learn that when designing a library, make sure when there are multiple implementations, derive them from the same interface. The FileInputStream here is a good example. InputStream defines the interface all its subclass should provide. And when it comes to specific implementation, those all go to the concrete class, so each implementation is defined in its own class, but we could swap to another implementation under circumstances we need to. Unit test is just one of them.

--

--