2012-09-26 19 views
1

我有類獲取GenericFile作爲輸入參數讀取數據並做一些額外的處理。我需要測試它:如何模擬FileInputStream和其他*流

public class RealCardParser { 

    public static final Logger l = LoggerFactory.getLogger(RealCardParser.class); 

    @Handler 
    public ArrayList<String> handle(GenericFile genericFile) throws IOException { 
     ArrayList<String> strings = new ArrayList<String>(); 
     FileInputStream fstream = new FileInputStream((File) genericFile.getFile()); 
     DataInputStream in = new DataInputStream(fstream); 
     BufferedReader br = new BufferedReader(new InputStreamReader(in)); 
     String strLine = br.readLine();//skip header 
     while ((strLine = br.readLine()) != null) { 
      l.info("handling in parser: {}", strLine); 
      strings.add(strLine); 
     } 
     br.close(); 
     return strings; 
    } 
} 

問題出在新的FileInputStream。我可以嘲笑GenericFile,但它是無用的,因爲FileInputStream檢查文件是否存在。所以,現在我可以重寫方法getBufferedReader和測試方法處理

public class RealCardParser { 

    public static final Logger l = LoggerFactory.getLogger(RealCardParser.class); 

    protected BufferedReader getBufferedReader(GenericFile genericFile) throws FileNotFoundException { 
     FileInputStream fstream = new FileInputStream((File) genericFile.getFile()); 
     DataInputStream in = new DataInputStream(fstream); 
     return new BufferedReader(new InputStreamReader(in)); 
    } 

    @Handler 
    public ArrayList<String> handle(GenericFile genericFile) throws IOException { 
     ArrayList<String> strings = new ArrayList<String>(); 
     BufferedReader br = getBufferedReader(genericFile); 
     String strLine = br.readLine();//skip header 
     while ((strLine = br.readLine()) != null) { 
      l.info("handling in parser: {}", strLine); 
      strings.add(strLine); 
     } 
     br.close(); 
     return strings; 
    } 
} 

:我改變了我的類,所以

@RunWith(MockitoJUnitRunner.class) 
public class RealCardParserTest { 

    RealCardParser parser; 

    @Mock 
    GenericFile genericFile; 

    @Mock 
    BufferedReader bufferedReader; 

    @Mock 
    File file; 

    @Before 
    public void setUp() throws Exception { 
     parser = new RealCardParser() { 
      @Override 
      public BufferedReader getBufferedReader(GenericFile genericFile) throws FileNotFoundException { 
       return bufferedReader; 
      } 
     }; 

     when(genericFile.getFile()).thenReturn(file); 
     when(bufferedReader.readLine()).thenReturn("header").thenReturn("1,2,3").thenReturn(null); 
    } 

    @Test 
    public void testParser() throws Exception { 
     parser.handle(genericFile); 
     //do some asserts 
    } 
} 

處理方法現在覆蓋測試,但我仍然發現,導致方法getBufferedReader cobertura問題。 如何測試方法getBufferedReader或者可能有另一個解決方案的問題?

+0

無關你的問題下面的代碼,但我認爲'makeBufferedReader'可能是比'getBufferedReader'這種方法更好的名字?對於大多數Java開發人員來說,以'get'開頭的名稱強​​烈建議您只是返回現有的屬性,而不是創造新的東西。 –

回答

2

也許這是一個壞主意,但我的第一種方法是創建一個實際的測試文件,而不是模擬流對象。

有人可能會爭辯說,這將測試GenericFile類而不是getBufferedReader方法。

也許一個可以接受的方式是通過模擬GenericFile返回一個實際存在的測試文件來測試getBufferedReader

+0

我想過但它不再是單元測試,而是一種集成測試 –

+0

我恐怕沒有看到任何方式。也許有更多寫作測試經驗的人可以在這裏幫忙。即使你在你的實現中拋棄了FileInputStream,就像@Jens所建議的那樣,你仍然需要在某個時候用「真實的東西」進行測試。 – Fildor

+0

內部創建的'java.io'對象可以用PowerMock或JMockit來模擬,但這裏最好的解決方案是這個答案建議使用一個實際的文件。只要'GenericFile'被嘲弄,它仍然是一個單元測試(雖然即使對於真實的對象也可以被使用)。然而,我在被測試的類中看到了多個質量問題(例如,返回'ArrayList'和發送無意義的調試信息等等)。 –

2

我會先將流的創建提取到依賴項中。所以你的RealCardParser獲得一個StreamSource作爲依賴。

現在你可以把你的APPART問題:

  1. 爲您當前的測試提供了一個模擬(或在這種情況下,我寧願一個假的)實現返回從String構造的流。

  2. 用真實文件測試實際的StreamSource,確保它返回正確的內容,而不是。

0

我知道這不是你想要的答案。

單元測試的想法是確保你的邏輯是正確的。單元測試可以捕獲錯誤邏輯寫入錯誤。如果一個方法不包含邏輯(即沒有分支,循環或異常處理),那麼對它進行單元測試是不經濟的。因此,我的意思是單元測試需要花費金錢 - 編寫它的時間,以及維護它的時間。大多數單元測試都是通過發現錯誤或者向我們保證在測試領域沒有錯誤來支付我們的投資。

但是您的getBufferedReader方法的單元測試不會爲您支付我們的投資。它具有有限的成本,但零利益,因爲沒有實際的邏輯可能出錯。因此,你不應該寫這樣的單元測試。如果您的Cobertura設置或您的組織標準要求存在這樣的單元測試,那麼這些設置或標準是錯誤的,應該改變。否則,你的僱主的錢將花在具有無限成本:收益比的東西上。

我強烈建議您更改標準,以便僅爲包含分支,循環或異常處理的方法編寫單元測試。

+0

那麼我理解你的文章,但我們的要求非常簡單,非常合乎邏輯:所有類(除了像基本類或自動生成的對象之類的基本類)都必須覆蓋大於80%的測試。由於該類足夠小,因此避免測試方法initBufferedReader導致代碼覆蓋率僅爲73%。談到該方法initBufferedReader沒有可能失敗的業務邏輯 - 我不同意。如果文件不存在並且存在可能會拋出異常的類型轉換,則可能會引發異常。 –

+1

當然,你應該測試處理你提到的那兩個異常的邏輯。但是,該邏輯並不在您的'getBufferedReader'方法中 - 它以任何方式_calls_「getBufferedReader」。因此,對於那些邏輯的測試屬於任何方法的測試。我相信接下來的唯一代碼覆蓋百分比是這些 - 您應該對代碼中的邏輯有100%的覆蓋率,對代碼沒有邏輯的覆蓋率爲0%。我認爲有一個單一的百分比(無論是60%還是90%)作爲組織標準是一個錯誤。 –

+0

我會upvote這個答案,如果它回答了這個問題。我真的很喜歡你所說的話,但它並沒有真正解決問題(關於嘲笑FileInputStream),這就是爲什麼我無法提供它的原因。好消息,否則。 – searchengine27

1

您可以使用PowerMockRunner和PowerMockito模擬FileInputStream。見mocking-

@RunWith(PowerMockRunner.class) 
@PrepareForTest({ 
     FileInputStream.class 
}) 
public class A{ 

@Test 
     public void testFileInputStream() 
        throws Exception 
     { 
      final FileInputStream fileInputStreamMock = PowerMockito.mock(FileInputStream.class); 
      PowerMockito.whenNew(FileInputStream.class).withArguments(Matchers.anyString()) 
           .thenReturn(fileInputStreamMock); 
    //Call the actual method containing the new constructor of FileInputStream 

     } 
} 
相關問題