总是阻止输入流进行测试?

时间:2011-07-06 23:41:12

标签: java testng mockito

我正在做一些单元测试,基本上我需要输入流永远阻止。现在我用它来构造输入流

InputStream in = new ByteArrayInputStream("".getBytes());

虽然它在某些时候有效,但有时在输出流(我正在测试的)之前读取输入流,导致各种各样的破坏。

基本上我需要这个输入流在读取时永远阻止。我能想到的唯一解决方案是使用一个巨大的缓冲区来设置InputStream,以便其他线程完成,但这是一个真正的hackish和脆弱的解决方案。我确实有嘲笑,但我很擅长它并且不确定我是否可以在没有嘲笑任何其他事情的情况下嘲笑阅读。

有谁知道更好的解决方案?


编辑:

这是我的新尝试。它大部分时间都有效,但有时输入线程会提前死亡,导致输出线程死亡(这种行为是有意的)。我似乎无法弄清楚为什么这有时会失败。

为了清楚起见,这是在TestNG下简化的一般测试。

    protected CountDownLatch inputLatch;

    @BeforeMethod
    public void botSetup() throws Exception {
            //Setup streams for bot
            PipedOutputStream out = new PipedOutputStream();
            //Create an input stream that we'll kill later
            inputLatch = new CountDownLatch(1);
            in = new AutoCloseInputStream(new ByteArrayInputStream("".getBytes()) {
                    @Override
                    public synchronized int read() {
                            try {
                                    //Block until were killed
                                    inputLatch.await();
                            } catch (InterruptedException ex) {
                                    //Wrap in an RuntimeException so whatever was using this fails
                                    throw new RuntimeException("Interrupted while waiting for input", ex);
                            }
                            //No more input
                            return -1;
                    }
            });
            Socket socket = mock(Socket.class);
            when(socket.getInputStream()).thenReturn(in);
            when(socket.getOutputStream()).thenReturn(out);

            //Setup ability to read from bots output
            botOut = new BufferedReader(new InputStreamReader(new PipedInputStream(out)));
            ...
    }

    @AfterMethod
    public void cleanUp() {
            inputLatch.countDown();
            bot.dispose();
    }

对于测试,我使用botOut中的readLine()来获得适当的行数。但问题是,当输出线程死亡时,readLine()将永久阻塞,从而挂起TestNG。我尝试了一个混合结果的超时:大部分时间它会起作用,但其他人会杀死测试只需要比正常情况稍微长一点的测试。

我唯一的另一种选择就是不要使用流来完成这类工作。输出线程依赖于输出队列,所以我可以运行它。但问题是我实际上并没有测试写入流,只是测试将要发送的内容,这会让我感到烦恼。

5 个答案:

答案 0 :(得分:2)

我创建一个InputStream,当read()时,对一些被锁定的东西执行wait(),直到你完成其余的测试。 FilterInputStream中的子类可以免费获取其他所有内容。

答案 1 :(得分:2)

Mockito很棒 - 我个人是个粉丝!

使用Mockito,您可以执行类似下面的代码。你基本上设置了一个流模拟器,并告诉它在很长一段时间内读取"读取"在它上面调用方法。然后,您可以将此模型传递到流要挂起时要测试的代码中。

import static org.mockito.Mockito.*;

//...
@Test
public void testMockitoSleepOnInputStreamRead() throws Exception{

    InputStream is = mock(InputStream.class);
    when(is.read()).thenAnswer(new Answer() {
        @Override
        public Object answer(InvocationOnMock invocation) {
            try {
            Thread.sleep(10000000000L);
            return null;
            } catch (InterruptedException ie) {
                throw new RuntimeException(ie);
            }

        }
    });

    //then use this input stream for your testing.
}

答案 2 :(得分:1)

似乎没有任何可靠的方法来做到这一点。我的问题中的代码有时只能起作用,@ Moe根本不起作用,@ Ed的建议就是我原来做的事情,@ SJuan是我正在做的事情。

似乎有太多东西在继续。我给类的输入流包装在一个InputStreamReader中,然后是一个Buffered读取器。对其他流内的其他流的建议只会使问题进一步复杂化。

为了解决这个问题,我做了我原本应该做的事情:为InputThread(实际执行读取的线程)创建一个工厂方法,然后在我的测试中覆盖。简单,有效,100%可靠。

我建议任何遇到此问题的人首先尝试覆盖执行阅读的程序部分。如果你不能,那么我发布的代码是唯一适用于我的情况的半可靠代码。

答案 3 :(得分:0)

然后你需要另一个InputStream风格。当没有更多字节可用时读取块,但是使用ByteArrayOutputStream,它们始终可用,直到找到流的末尾。

我会通过更改read()来扩展BAOS,因此它会检查某个布尔值(如果为true,则为false,等待一秒钟并循环)。然后在合适的时间从单位代码中更改该变量。

希望有所帮助

答案 4 :(得分:0)

我创建了一个帮助类,它扩展了ByteArrayInputStream以进行单元测试。它管理给定的int,但在流的末尾而不是返回byte[],它等待直到-1被调用。如果超过10秒,它就会放弃并抛出异常。

如果您希望提前关闭,可以自己致电close()

latch.countdown()