2014-12-28 217 views
1

我是新困惑。我對我應該測試和驗證的內容感到困惑。我有一個類如下:通過單元測試和單元的Mockito和測試的Mockito

public class A{ 
    @Autowired 
    private B b; 

    public double doSomething(Request r){ 
     r = b.process1(r); 
     r = b.process2(r); 
     return calculateFinal(r); 
    } 

    public void reportSomething(Request r){ 
     r = b.process1(r); 
     r = b.process2(r); 
     b.report(r); 
    } 

    private int calculateFinal(Request r){ 
     return r.getFinalScore() * 2; 
    } 
} 

假設我想用Junit測試來測試這兩種方法。由於我在A中有一個依賴關係B,所以我用Mockito來嘲笑它。對於這兩種測試中,有人告訴我,我應該承擔的依賴b的全面測試和正常工作,因爲我們要測試的業務邏輯A.

起初它看起來像我沒有測試任何東西對於reportSomething(),因爲它只涉及撥打b,他們都「工作」?我能想到的唯一要測試的是他們是否真的被調用,調用的順序是否正確?所以我應該只需調用a.reportSomething()然後進行驗證?有一點讓我感到困惑的是,我是否應該存根b.process1()和b.process2()來返回任何東西。我嘗試了沒有琢磨任何東西,它的工作原理,但爲什麼?

對於testDoSomething(),我想我真正的測試是calculateFinal()方法。但是由於它使用來自Request對象的數據,所以我需要首先在請求r中設置這些數據。由於r直接來自b.process2(),我應該存根方法調用以返回具有該數據的Request對象。但我可以跳過b.process1()的殘局,對吧?

這是一個正確的思維過程?我錯過了什麼或誤解了什麼?如果它是正確的,是否有更好更清潔的方式來編寫它?謝謝!

public class ATest{ 
    private static final int SCORE = 100; 

    @Mock 
    private B mockB; 

    @InjectMocks 
    private A aClient; 

    @Before 
    public void setUpTest{ 
     MockitoAnnotations.initMocks(this); 
    } 

    @Test 
    public void testReportSomething(){ 
     // what should I test here? 

     Request r = new Request(); 

     // is it necessary to include the following two lines? 
     when(mockB.process1(any(Request.class))).return(r); 
     when(mockB.process2(any(Request.class))).return(r); 


     aClient.reportSomething(r); 
     InOrder inOrder = inOrder(mockProcesser); 
     inOrder.verify(mockProcesser).process1(any(Request.class)); 
     inOrder.verify(mockProcesser).process2(any(Request.class)); 
     inOrder.verify(mockProcesser).report(any(Request.class)); 
    } 

    @Test 
    public void testDoSomething(){ 
     // Is this correct? 
     Request r = new Request(); 
     r.setFinal(SCORE); 

     // I skipped this line and it still works 
     when(mockB.process1(any(Request.class))).return(r); 

     when(mockB.process2(any(Request.class))).return(r); 
     assert(SCORE * 2, aClient.doSomething(r)); 
     // is it still necessary to verify the call to mockB? 
    } 
} 

回答

2

您正在錯誤地做你的測試。讓我們來看看該方法要測試:

public void reportSomething(Request r){ 
    r = b.process1(r); 
    r = b.process2(r); 
    b.report(r); 
} 

首先,你需要模擬是當B處理的請求時,它返回預期結果;因此不要在兩次調用中使用相同的返回值。

這是我會怎麼寫測試:

final Request r = mock(Request.class); 
final Request r1 = mock(Request.class); 
final Request r2 = mock(Request.class); 

when(mockB.process1(r)).thenReturn(r1); 
when(mockB.process2(r1)).thenReturn(r2); 
doNothing().when(mockB).report(any(Request.class)); 

final InOrder inOrder = inOrder(mockB); 

// Launch... And then verify: 

inOrder.verify(mockB).process1(r); 
inOrder.verify(mockB).process2(r1); 
inOrder.verify(mockB).report(r2); 
inOrder.verifyNoMoreInteractions(); 

至於:

// is it necessary to include the following two lines? 

是。默認情況下,未指定時,模擬實例將返回Java的默認值:數字基元爲0,布爾值爲false,對象爲null。你必須指定你想要通過存根返回的東西。

+0

因此,即使我們知道了依賴B工作正常,我們仍然需要通過「b時處理一個請求時,它會返回預期的結果」嘲笑呢?另外,爲什麼'doNothing()。when(mockB).report(any(Request.class));'but not'doNothing()。when(mockB).report(r2);'?謝謝。 – SteelwingsJZ

+0

'b'可以正常工作,但在這裏你不測試'B';就像第二點一樣,它是擴大存根的範圍。驗證是重要的,並且你想要測試'b.report()'是否被'r2'調用。 – fge

+2

在附註中,我會在代碼完成後添加該測試通常會非常棘手,因爲代碼對測試友好性要差得多。如果需要嘲笑,這將變得更加微妙而不重構。 – Brice

相關問題