2017-02-11 131 views
1

我想要做的是模擬BufferedReader新創建的實例。這裏是一個應該被測試代碼:PowerkMocking BufferedReader緩慢運行

A.java

... 
@Override 
public String read(String fileName) throws IOException { 
    ... 

    try { 
     fileReader = new FileReader(fileName); 
     bufferedReader = new BufferedReader(fileReader); 
     String tmp; 
     StringBuilder builder = new StringBuilder(); 
     while ((tmp = bufferedReader.readLine()) != null) { 
      builder.append(tmp); 
     } 
     return builder.toString(); 
    } catch (IOException e) { 
     ... 
    } finally { 
     ... 
    } 
} 
... 

我要做的,就是既PowerMock創建FileReaderBufferedReader創作。

ATest.java

@RunWith(PowerMockRunner.class) 
@PrepareForTest(A.class) 
public class ATest { 

    @Mock 
    private FileReader fileReader; 
    @Mock 
    private BufferedReader bufferedReader; 
    ... 

    @Test 
    public void test() throws Exception { 
     PowerMockito.whenNew(FileReader.class).withArguments(FILE_NAME).thenReturn(fileReader); 
     PowerMockito.whenNew(BufferedReader.class).withAnyArguments().thenReturn(bufferedReader); 
     PowerMockito.doAnswer(new Answer() { 
      public Object answer(InvocationOnMock invocation) throws Throwable { 
       return "test"; 
      } 
     }).when(bufferedReader).readLine(); 
     assertArrayEquals(reader.read(FILE_NAME), new String[]{"test"}); 
    } 
} 

但隨後的測試永遠不會終止。我甚至無法調試它。

只要PowerMockito.doAnswer()被移除,代碼就會被執行(並且可用於調試)。我也嘗試使用Mockito.mock()而不是PowerMockito.doAnswer(),它沒有幫助。

什麼可能會導致測試的中斷執行?

回答

1

問題是,我還必須在第一個bufferedReader.readLine()後模擬值,因爲否則它總是會返回模擬值,因此不會終止。

Mockito.when(bufferedReader.readLine()).thenReturn("first line").thenReturn(null); 

注意

雖然這是實際的問題的答案,但你應當認真考慮在另一個答案選擇設計GhostCat has suggested(我最終沒有)。

3

只是一個不同的觀點:人們可以說你的代碼中的真實問題是對FileReader/BufferedReader的new()的兩次調用。

如果您將Reader傳遞給此方法會怎樣?而不是一個字符串表示文件名?

如果您將「ReaderFactory」傳遞給包含此方法的基礎類,該怎麼辦?read(String)? (在這裏您將使用依賴注入到工廠進入類)

然後:你會在看一個改進設計 - 你會不會需要使用PowerMock。你可以退後一步,並與Mockito或EasyMock一起去;因爲將不再需要模擬new的呼叫。

所以,我的答案是:你創建了難以測試的代碼。現在,您嘗試使用大型(醜陋)PowerMock錘子修復設計問題。是的,那會起作用。但它只是第二好的選擇。

更合理的選擇是學習如何編寫可測試代碼(例如,開始here);並編寫可測試的代碼。並停止使用PowerMock(我已經完成了那麼多個月;經過了很多PowerMock引起的痛苦;並且我有永遠不會後悔這個決定)。

+0

謝謝,非常有道理。 – azizbekian

+1

非常歡迎。我總是很高興,當人們不回覆這樣的答案時,「但它不是我的代碼,我必須測試;所以PowerMock是我的唯一選擇」;-) – GhostCat

+1

而且正如旁註:FileUtilities.readAllLines ) - 接受一個字符串,並返回該文件中所有行的列表(您可以輕鬆地連接以獲取單個字符串)。因此,可能不是重新實現第10次「完全讀入字符串」,您也可以使用其中一個現有的實現。我確定apache commons,番石榴,他們都有這個方法! – GhostCat