How can I unit test this inputStream has been closed?

To check if the close() method is called, you can use Mockito.spy() to create a proxy object that can memorize calls. Spy delegates all the calls to the underlying InputStream, just memorizes what happened:

InputStream inputStreamSpy = Mockito.spy(inputStream);
// a code that is expected to close your stream goes here ...
Mockito.verify(inputStreamSpy).close();

This won't solve your problems with injecting instance of InputStream, actually. It seems like you need some kind of factory, that can open a stream for you, and you can mock that factory in unit tests. Let's call this factory a FileSystem:

public class FileSystem {
    public FileInputStream newFileInputStream(File file) {
        return new FileInputStream(file);
    }
}

Now, you can inject an instance of the FileSystem, and it won't use resources before run method is executed:

public void run() {
    InputStream inputStream = null;
    try {
        inputStream = fileSystem.newFileInputStream(file);
        //more stuff here
    } 
    catch (Exception e) {
        //simplified for reading
    }
    finally {
        if(inputStream != null) {
            try {
                inputStream.close();
            } catch (IOException e) {}
        }
    }
}

@Test
public void runShouldCloseInputStream() {
    InputStream inputStream = ...
    InputStream inputStreamSpy = Mockito.spy(inputStream);
    FileSystem fileSystemMock = Mockito.mock(FileSystem.class);
    when(mockFileSystem.newFileInputStream(Mockito.any(File.class)))
        .thenReturn(inputStreamSpy);

    MyRunnable instance = new MyRunnable(mockFileSystem);
    instance.run();

    verify(inputStreamSpy).close();
}

Spy can do more then just listening, you can teach it to alter behavior using Mockito.when(), just as you would do with a regular mock.


If I understood the task correctly it could be like this

static boolean isClosed;

public void run() {
    InputStream inputStream = null;
    try {
        inputStream = new FileInputStream(file) {
            @Override
            public void close() throws IOException {
                isClosed = true;
                super.close();
            }
        };
        // more stuff here

As there is no reason to expose the InputStream outside of the scope of this method you have a testing problem.

But I assume you don't directly care about the InputStream being closed. You want to test that because you've been told it's good practice (and it is). But I think what you actually care about is the negative impact of the stream being left open. What is the effect?

Try modifying this method so it does not close the stream, then execute it many times over. Do you get a memory leak, or run out of file handles or some other tomfoolery? If so, you have a reasonable test.

Alternatively, just go ahead and expose a decorated InputStream that can tell you if it has been closed or not. Make it package protected. That's the "impure", but pragmatic approach.