java 如何对这个 inputStream 已关闭进行单元测试?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13800269/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 14:01:31  来源:igfitidea点击:

How can I unit test this inputStream has been closed?

javaunit-testingjunitmockito

提问by mogronalol

I have a Runnablealong the lines of:

我有以下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) {}
            }
        }
    }

How do I test inputStream.close()was invoked? I am currently using Mockito and JUnit. I know injecting the inputStreamin is an idea, but I don't want the resources to be used until run?()is called, hence it being a local variable. So how can I redesign my code in a way that allows me to test whether close was called?

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

回答by Evgeniy Dorofeev

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

回答by Synesso

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

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

But I assume you don't directly care about the InputStreambeing 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?

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

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.

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

回答by Piotr

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:

要检查 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();

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:

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

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:

现在,您可以注入 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 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.

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

回答by Tom

Kotlin implementation for testing a URL stream is closed

用于测试 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) }

回答by Dedyshka

You can write in the test something like:

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

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

When your method will close strem and exception will occur, then test will fail.

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

回答by Jason

You can do like this...

你可以这样做...

    try
    {
         inputStream.readLine();        
    }
    catch (IOException e)
    {
        Assert.assertEquals(e.getLocalizedMessage(), "Stream closed");
    }