2012-08-13 69 views
33

我正在尋找一種方法來驗證Mockito,在測試過程中沒有任何與給定模擬的交互。對於具有驗證模式never()的給定方法很容易實現,但是我還沒有找到完整模擬的解決方案。Mockito - 如何驗證模擬從未被調用

我實際上想達到的目標:在測試中驗證,沒有任何東西會打印到控制檯。使用JUnit的總體思路是這樣說:

private PrintStream systemOut; 

@Before 
public void setUp() { 
    // spy on System.out 
    systemOut = spy(System.out); 
} 

@After 
public void tearDown() { 
    verify(systemOut, never()); // <-- that doesn't work, just shows the intention 
} 

一個PrintStream擁有噸的方法,我真的不希望驗證每一個有獨立的驗證 - 與同爲System.err ...

所以我希望,如果有一個簡單的解決方案,我可以,因爲我有一個很好的測試覆蓋率,迫使軟件工程師(和我)在提交更改之前刪除他們的(我的)調試代碼,如System.out.println("Breakpoint#1");e.printStacktrace();

回答

37

使用此:

解決這個問題的
import static org.mockito.Mockito.verifyZeroInteractions; 

// ... 

private PrintStream backup = System.out; 

@Before 
public void setUp() { 
    System.setOut(mock(PrintStream.class)); 
} 

@After 
public void tearDown() { 
    verifyZeroInteractions(System.out); 
    System.setOut(backup); 
} 
+0

看起來像我可以做的最好的方法。謝謝! (我實際上把大部分邏輯都隱藏在助手類中,並且不得不讓沉默記錄器) – 2012-08-13 15:51:58

6
verifyZeroInteractions(systemOut); 

正如在評論中指出的,這不適用於間諜。

對於一個大致等價但更完整的答案,請參閱gontard對此問題的答案。

+0

(facepalm) - 但它似乎沒有與間諜工作,我必須嘲笑一個PrintStream,而不是設置它在系統上... – 2012-08-13 14:35:41

+0

沒有看到你的代碼,我猜測爲什麼這會失敗的原因間諜是,當你存留間諜時,存根中的方法調用實際上算作一個被驗證的方法。三點建議。 (1)'verifyNoMoreInvocations(ignoreStubs(mockOne,mockTwo));' - 這將像'verifyZeroInteractions'一樣工作,但是忽略你已經存在的東西。 (2)您是否使用'doReturn/doThrow/doAnswer'方法來設置存根?當處理間諜時,這些通常比'當......',然後返回/ thenThrow/then'的效果更好。 ...繼續 – 2012-08-13 21:29:31

+0

建議(3)是發佈一些更多的代碼,以便這裏的人可以更好地幫助你。 – 2012-08-13 21:29:50

4

你可以嘗試一個稍微不同的策略:

private PrintStream stdout; 

@Before public void before() { 
    stdout = System.out; 
    OutputStream out = new OutputStream() { 
     @Override public void write(int arg0) throws IOException { 
      throw new RuntimeException("Not allowed"); 
     } 
    }; 
    System.setOut(new PrintStream(out)); 
} 

@After public void after() { 
    System.setOut(stdout); 
} 

如果首選,您可以切換匿名類型的模擬和驗證as Don Roby suggests

+1

肯定是+1。不幸的是,我這次對Mockito的解決方案很感興趣,所以我會接受另一個答案。希望你不介意:) – 2012-08-13 15:50:17

2

一種方法是重構你正在測試的類,允許可用於輸出的PrintStream的注入。這可以讓你單元測試它,而不依賴System類的行爲。您可以使用包私有構造函數進行此注入,因爲您只能從相應的測試類中使用它。所以它可能看起來像這樣。

public class MyClass{ 
    private PrintWriter systemOut; 

    public MyClass(){ 
     this(System.out); 
    } 

    MyClass(PrintWriter systemOut){ 
     this.systemOut = systemOut; 

     // ...any other initialisation processing that you need to do 
    } 
} 

和類本身,使用systemOut變量而不是System.out的,無論你稱後者。

現在,在測試類中,製作一個模擬PrintStream,並將它傳遞給包私有構造函數,以獲取您要測試的對象。現在,您可以在測試中運行您喜歡的任何操作,並使用verify檢查它們對模擬PrintStream的影響。

+0

啊,好的,但不是我想要做的:我試圖找到一種方法來測試一個類而不觸摸它,特別是不添加僅用於測試的代碼。但另一方面,如果我們願意準備被測試的課程,那麼這真是一個很好的方法! – 2012-08-14 12:43:37