簡體   English   中英

單元測試斷言 vs Mockito.verify()

[英]Unit tests assert vs Mockito.verify()

擺弄 Mockito 來實現我的服務的單元測試,但由於某種原因,我無法通過我厚實的頭骨得到這個。 我的測試通過了,但我不相信我做對了。

這是我測試 count() 方法的示例。 該方法只是將調用轉發到其存儲庫,我不想驗證僅此而已,沒有其他任何事情發生。 這就是我所擁有的:

@RunWith(MockitoJUnitRunner.class)
public class PersonServiceImplTest {

    @Mock
    private PersonRepository personRepository;

    @InjectMocks
    private PersonServiceImpl personService;

    @Test
    public void testCount() {

        when(personRepository.count()).thenReturn(2L);

        long count = personService.count();

        assertEquals(2L, count);

        verify(personRepository).count();
    }
}

我的測試通過了,但我有一些問題。

  1. 是否需要 assertEquals? 據我了解,無論我把什么作為方法存根 (.thenReturn(value..)) 的預期結果,都將始終是返回的值。 還是在這種情況下可能是其他原因?

  2. 我需要驗證嗎? 我覺得我這樣做是因為我想驗證是否確實調用了 personRepository.count() 。 或者當我也有 assertEquals() 時那是多余的嗎?

  3. 我需要 assertEquals 和驗證嗎?

  4. 最后,我這樣做對嗎:)

謝謝

為了:

  1. 是否需要assertEquals()取決於。 返回之前, personServicepersonRepository.count()的結果是否有任何改變的可能? 如果答案是“絕對不是”,那么您可能不需要assertEquals() -但是,如果有可能出現問題,則assertEquals()將確保沒有錯。

  2. 您是否需要verify()這取決於。 是否有可能沒有調用personRepository.count() 還是它被多次調用verify()默認情況下verify()期望其參數被精確調用一次)? 如果不是,那么您可能不需要它。

  3. 您是否需要兩者:它取決於(注意到一種模式?)。 見上文:他們做了不同的事情。 在很多情況下,您都希望同時檢查這兩種情況:1.返回正確的結果,並且2.通過執行您希望做的事情來返回結果。

  4. 您做對了嗎:好吧...這取決於。 personRepository.count()看起來像personRepository.count()

     public int count() { return this.personService.count(); } 

如果是這樣,您可能根本不需要太多測試。 如果您堅持要進行測試,則跳過verify()可能還可以,因為上面的方法除了調用要verify的函數外沒有其他方法來獲取值 ,並且它返回該值,因此幾乎無法調用它不止一次。

另一方面,如果您的函數如下所示:

public int count() {
    // get a personService from an injector
    // log the personService's details
    // generate a random number
    // try calling count() on personService, catch an error
    // if you caught the error, return the random number
}

然后,也許您確實verify()因為突然之間,發生了很多事情,即使有些事情出了嚴重問題,也可能會混淆其中的一些(即隨機數)以確保功能正常。

是的,您做對了。

您正在將模擬存儲庫注入到真實服務中,然后測試該服務。 當涉及到服務中的業務邏輯時,可能會發生任何事情。 這就是為什么像您所做的那樣,用已知的輸入和已知的輸出來驗證代碼很重要。

  1. 給定存儲庫的響應,您正在檢查業務邏輯的結果。 這個特定的代碼非常簡單,但是可以想象一下,業務邏輯是在提供平均值還是總和,而不僅僅是從存儲庫提供的相同值。

  2. 3.verify和assertEquals正在測試不同的東西。 驗證檢查您的存儲庫方法是否被調用,斷言檢查服務是否以正確的值響應。 想象一下,您的服務方法有一個硬編碼的return 2L assertEquals將通過,但驗證將失敗。

  3. 是的,您做對了。 您要測試的內容與您要測試的原因有關。 是否需要特定的斷言或驗證通常取決於具體情況。 在這種情況下,測試存儲庫方法返回2L毫無意義,但是測試服務返回2L是一個很好的例子。 同樣,測試服務方法已被調用沒有任何意義,但是測試存儲庫方法已被調用的情況很好。

現在,您已經具有測試服務的工具,下一步是確定要編寫的測試。

最好通過構造函數而不是@InjectMocks注入PersonRepository 這也消除了對特定運行器的需求(或者,在您的測試后期,涉及Spring的低級測試)。

您對Mockito的使用是正確的,但不是最佳方法。 您確實需要assertEquals因為要測試的是該服務返回的值與您從存儲庫提供的值相同。 不需要verify...count因為這是通過檢查是否返回了適當的值來暗示的。 您可以通過返回一個隨機數而不是2來改善這一點。

還要檢查是否真的值得將count()包裝在另一個對象中,或者只是添加不必要的層。

最后,您可以考慮檢查Spock 它是JUnit之上基於Groovy的測試語言,提供了一種干凈而強大的模擬語言。

我可以從你的測試中得到這些東西:

  • 您正在對服務層進行單元測試(*)

     @InjectMocks private PersonServiceImpl personService;
  • 您的測試方法是白盒(**)

    驗證(personRepository).count();

(*) 是因為您使用真正的 object 作為服務,使用 mocking 其他所有內容(因為@InjectMocks 將嘗試使用模擬存儲庫作為依賴實例化您的服務)

(**) 是因為您關心系統的工作方式(對 Service.count() 的調用反過來會分派對 Repository.count() 的調用)。

基於該假設,以下是您問題的答案(不按您的順序):

2.

我需要驗證嗎?

這取決於你關心什么:

  • 如果您關心服務應該如何在幕后工作,也就是進行白盒測試(例如:服務必須將調用分派到存儲庫,而不是硬編碼值),您確實需要驗證來強制實施設計。 將來,您的測試可能會失敗,您會知道失敗是否符合預期(實施設計更改或錯誤修復副作用等)。 在采用這種方法時,您應該考慮添加更多測試:是否打印了日志? repository.count() 是否只被調用一次? 等等。請參閱White-box_testing

  • 如果您關心調用service.count()或進行黑盒測試時的結果是什么,則無需驗證方法調用。 相反,您應該考慮添加更多測試:IS service.count() 0 when repository.count() is 0? repository.count() 拋出異常時,service.count() 是否拋出異常? 請參閱Black-box_testing

    因為我們必須存根存儲庫的 count() 來測試服務的 count(),人們通常會將這種方法與白盒測試混淆,但這不是因為我們關心 service.count() 返回該值時的上下文,不怎么樣。

  • 當然,您可以關心結果是什么以及結果是如何計算的,但不建議這樣做,因為這會使您的測試變得復雜且難以維護。

我需要 assertEquals 和驗證嗎?

同樣,我假設您正在進行白盒測試。 盡管您正在進行白盒測試 - 驗證在這里更重要,但建議至少進行 1 次健全性測試。 所以在這種情況下你做得對。

1.

是否需要 assertEquals?

如上所述,是的,需要assertEquals

據我了解,無論我把什么作為方法存根 (.thenReturn(value..)) 的預期結果,都將始終是返回的值。

  1. 您正在存根存儲庫 class 的方法,這是一個依賴項 - 而不是您的測試目標(服務)
  2. 您正在斷言測試目標(服務)的結果

所以你做得對。

4.

最后,我這樣做對嗎:)

我認為這是一個很好的典型白盒測試:)

參考:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM