【问题标题】:Testing outputstream.write(<String>) without creating a file在不创建文件的情况下测试 outputstream.write(<String>)
【发布时间】:2012-02-17 12:26:42
【问题描述】:

我正在用 java 测试一个输出流,如下所示。

    Writer outputStream = getOutputStream(fileName);
    if(outputStream != null) {
        try {
            outputStream.write(inputText);
        }
        finally {
            outputStream.close();
        }
    }
    else {
        throw new IOException("Output stream is null");
    }

我正在编写如下模拟测试

public void testFileWrite() throws IOException {
    when(testObj.getOutputStream(outputFileNameValidValue)).thenReturn(outputStreamMock);
    doNothing().when(outputStreamMock).write(Matchers.anyString());
    doNothing().when(bufferedReaderMock).close();

    testObj.write(outputFileNameValidValue, reveredFileInput);

    verify(outputStreamMock).write(Matchers.anyString());
    verify(outputStreamMock).close();
}

问题是当您创建OutputStreamWriter(new FileOutputStream(filename)) 时,会在磁盘上创建一个物理文件。

我们可以测试Outputstream.write 而不实际在磁盘上写入文件吗?

谢谢 阿南德

【问题讨论】:

  • 请澄清 - 你在哪里创建 OutputStreamWriter - 我在你的代码中看不到它。我猜它在getOutputStream 之内——除了你已经取消了这个方法。如果您希望人们做好帮助您的工作,您需要发布所有代码。此外,getOutputStream 可能应该被称为其他名称(可能是 makeWriter),因为它没有得到 OutputStream
  • 在 getOutputStream 方法中。我将其移至方法的原因是希望 mockito 不会运行 mthod 并返回 mock。但我错了。
  • 在谷歌搜索和阅读一些文档后发现 PowerMock 可以轻松做到这一点。使用 expectNew 或使用 suppressConstructor 和 Whitebox.setInsternalState。使用 PowerMock 测试这些东西要容易得多。感谢大家的 cmets 和回答.. 问候,Anand Barhate

标签: java testing tdd mockito


【解决方案1】:

您可以使用 ByteArrayOutputStream 将数据写入内存。您可以使用 ByteArrayInputStream 阅读此内容。

另一种方法是编写一个预期的 OutputStream,一旦您尝试写入不正确的字节,它就会失败。这有助于准确了解测试失败的位置/原因。

【讨论】:

  • Ok.. 所以使用 ByteArrayOutputStream 写入,然后最终我将不得不使用 writeTo 写入文件?但迟早我会面临同样的问题,不是吗? XXStreamWriter 将不得不写入文件,这是我想避免使用 Mockito 的一点。
  • 我不明白。为什么需要写入文件?
【解决方案2】:

您可以尝试使用 System.out 作为您的输出,它实际上是一个 Printstream,它是 OutputStream 的子类

见: http://docs.oracle.com/javase/6/docs/api/java/lang/System.html http://docs.oracle.com/javase/6/docs/api/java/io/PrintStream.html

【讨论】:

    【解决方案3】:

    正如其他人已经建议的那样,您需要能够在您的测试类中注入一个模拟的 OutputStream。由于您的测试类需要一个写入给定文件的 OutputStream,您需要将一个可模拟的 OutputStreamFactory 注入您的测试类。

    我有这个完全独立的代码:

    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.Mock;
    import org.mockito.runners.MockitoJUnitRunner;
    
    import java.io.IOException;
    import java.io.OutputStream;
    
    import static org.mockito.Mockito.verify;
    import static org.mockito.Mockito.when;
    
    @RunWith(MockitoJUnitRunner.class)
    public class Test9328173 {
    
        private ClassUnderTest testObj;
    
        @Mock
        private OutputStreamFactory factory;
    
        @Mock
        private OutputStream stream;
    
        @Before
        public void setUp() throws Exception {
            testObj = new ClassUnderTest();
            testObj.factory = factory;
        }
    
        @Test
        public void testFileWrite() throws Exception {
            when(factory.create("filename")).thenReturn(stream);
    
            testObj.write("filename", new byte[]{1, 2, 3});
    
            verify(stream).write(new byte[]{1, 2, 3});
            verify(stream).close();
        }
    
        private class ClassUnderTest {
    
            private OutputStreamFactory factory;
    
            public void write(String filename, byte[] content) throws IOException {
                OutputStream stream = factory.create(filename);
                try {
                    stream.write(content);
                } finally {
                    stream.close();
                }
            }
        }
    
        private interface OutputStreamFactory {
    
            OutputStream create(String filename);
        }
    }
    

    【讨论】:

    • 确实如此。一个 setter/constructor 参数/@Inject 注解可能比工厂简单一点,但这是验证流接收到正确指令的方法。
    【解决方案4】:

    你应该模拟你的getOutputStream: 应该返回模拟的输出流对象。调用new FileOutputStream 确实会在磁盘上创建文件。

    理论上你可以模拟文件系统本身,但它要复杂得多。

    顺便说一句,if(outputStream != null) 是多余的:流永远不能为空。如果它不能被创建,该方法应该抛出异常。它不是 C,它是 Java。 :)

    【讨论】:

    • 其实这就是我做when(testObj.getOutputStream(outputFileNameValidValue)).thenReturn(outputStreamMock);但是当我调用 testObj.write(outputFileNameValidValue, reveredFileInput);它仍然会将空白字符串写入文件。所以看来我必须模拟文件系统以避免在磁盘上实际创建文件。
    • if(outputStream != null) 同意这一点。我只是习惯于防御性编程:)
    【解决方案5】:

    您应该让模拟的getOutputStream(String) 返回一个java.io.StringWriter,然后您可以断言预期的内容已写入。

    public void testFileWrite() throws IOException {
        StringWriter writer = new StringWriter();
        when(testObj.getOutputStream(outputFileNameValidValue)).thenReturn(writer);
    
        testObj.write(outputFileNameValidValue, reveredFileInput);
    
        assertEquals(reveredFileInput, writer.toString());
    
        verify(writer).close();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-30
      • 1970-01-01
      相关资源
      最近更新 更多