14

我有一个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) {}
            }
        }
    }

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

4

6 回答 6

18

如果我正确理解了任务,它可能是这样的

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
于 2012-12-10T11:47:36.737 回答
7

由于没有理由在此方法范围之外公开 InputStream,因此您遇到了测试问题。

但我假设你并不直接关心InputStream被关闭。你想测试它,因为你被告知这是一种很好的做法(而且确实如此)。但我认为你真正关心的是保持开放的流的负面影响。效果如何?

尝试修改此方法,使其不关闭流,然后多次执行。您是否遇到内存泄漏,或者文件句柄用完或其他一些愚蠢的行为?如果是这样,你有一个合理的测试。

或者,继续并公开一个装饰的 InputStream ,它可以告诉您它是否已关闭。使其包保护。这就是“不纯”但务实的做法。

于 2012-12-10T11:48:12.653 回答
7

要检查是否调用了 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 实例的问题。似乎您需要某种可以为您打开流的工厂,并且您可以在单元测试中模拟该工厂。让我们称这个工厂为 FileSystem:

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

现在,您可以注入 FileSystem 的一个实例,并且在执行 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();
}

Spy 可以做的不仅仅是聆听,您可以使用 Mockito.when() 教它改变行为,就像使用常规模拟一样。

于 2017-03-08T03:42:43.200 回答
1

用于测试 URL 流的 Kotlin 实现已关闭

//close the connection
streamURL.close()

//stream should not be available if it is closed
try { streamURL.available() }

//java.net.URL provides simple "closed" message on IO URL
catch (ex: IOException) { Assert.assertEquals("closed", ex.message) }
于 2019-02-15T11:16:40.387 回答
0

您可以在测试中编写如下内容:

try {
    run();
} catch (IOException e) {
    Assert.fail();
}

当您的方法关闭 strem 并发生异常时,测试将失败。

于 2012-12-10T13:33:24.423 回答
0

你可以这样做...

    try
    {
         inputStream.readLine();        
    }
    catch (IOException e)
    {
        Assert.assertEquals(e.getLocalizedMessage(), "Stream closed");
    }
于 2015-06-12T17:48:14.607 回答