如何对这个输入流已关闭进行单元测试?

2022-09-03 17:35:15

我有一个大致如下:Runnable

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

如何测试被调用?我目前正在使用Mockito和JUnit。我知道注入是一个想法,但我不希望在调用之前使用资源,因此它是一个局部变量。那么,如何重新设计我的代码,使我能够测试是否调用了 close?inputStream.close()inputStreamrun?()


答案 1

如果我正确地理解了这个任务,它可能会像这样

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

答案 2

要检查是否调用了 close() 方法,可以使用 Mockito.spy() 创建一个可以记住调用的代理对象。Spy将所有调用委托给底层的 InputStream,只是记住发生了什么:

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

实际上,这并不能解决注入 InputStream 实例的问题。看起来你需要某种工厂,它可以为你打开一个流,你可以在单元测试中模拟那个工厂。让我们将此工厂称为文件系统:

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

现在,您可以注入文件系统的实例,并且在执行 run 方法之前它不会使用资源:

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();
}

间谍可以做更多的事情,而不仅仅是倾听,你可以教它使用Mockito.when()改变行为,就像你用常规模拟一样。


推荐