2012-02-17 68 views
9

我正在測試java中的輸出流,如下所示。在不創建文件的情況下測試outputstream.write(<String>)

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

我寫一個測試的Mockito如下

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而無需在磁盤上實際寫入文件嗎?

感謝 阿南德

+1

請澄清 - 你在哪裏創建'OutputStreamWriter' - 我沒有看到它在你的代碼。我猜想它在'getOutputStream'內 - 除了你已經將這個方法存根了。如果你希望人們能夠很好地幫助你,你需要發佈你的所有代碼。此外,'getOutputStream'可能應該被稱爲別的東西(也許'makeWriter'),因爲它沒有得到'OutputStream'。 – 2012-02-18 00:53:30

+0

在getOutputStream方法中。我之所以把它移到這個方法上,是希望mockito不會運行方法並返回模擬。但我錯了。 – Anand 2012-02-18 06:22:30

+0

谷歌搜索和閱讀很少的文檔後發現,PowerMock可以很容易地做到這一點。使用expectNew或使用suppressConstructor和Whitebox.setInsternalState。用PowerMock測試這些東西很容易。謝謝你的意見和答案..問候,阿南德巴爾哈特 – Anand 2012-02-18 06:24:51

回答

9

您可以使用ByteArrayOutputStream其在內存中寫入數據。你可以用ByteArrayInputStream讀取它。

另一種方法是編寫一個期望的OutputStream,只要您嘗試寫入不正確的字節,就會失敗。這可以幫助您準確查看測試失敗的原因/原因。

+0

好吧..所以使用ByteArrayOutputStream來寫,然後最終我將不得不使用writeTo寫入文件?但遲早我會面臨同樣的問題,不是嗎? XXStreamWriter將不得不寫入文件,這是我想避免使用Mockito的一點。 – Anand 2012-02-17 12:42:03

+1

我不明白。爲什麼你需要寫入一個文件? – 2012-02-17 12:45:21

0

你應該嘲笑你的getOutputStream:應該返回模擬輸出流對象。調用new FileOutputStream確實在磁盤上創建了文件。

理論上你可以模擬文件系統本身,但它更復雜。

而BTW if(outputStream != null)是多餘的:流永遠不能爲空。如果無法創建,該方法應拋出異常。它不是C,它是Java。 :)

+0

其實這是我做的\t \t when(testObj.getOutputStream(outputFileNameValidValue))。thenReturn(outputStreamMock); 但是當我打電話\t \t testObj.write(outputFileNameValidValue,reveredFileInput); 它仍然會將空字符串寫入文件。因此,我似乎必須嘲笑文件系統,以避免在磁盤上實際創建文件。 – Anand 2012-02-17 12:46:36

+0

if(outputStream!= null)同意這一點。我只是習慣於防禦性編程:) – Anand 2012-02-17 12:48:48

0

你應該有嘲笑的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(); 
} 
1

或其他建議已經需要能夠注入嘲笑的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); 
    } 
} 
+0

確實。 setter/constructor參數/ @Inject註釋可能比工廠更容易一些,但這是驗證流接收正確指令的方法。 – avandeursen 2012-03-07 09:55:52

相關問題