![](/img/trans.png)
[英]Using Mockito.when() to mock and verify 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();
}
}
我的測試通過了,但我有一些問題。
是否需要 assertEquals? 據我了解,無論我把什么作為方法存根 (.thenReturn(value..)) 的預期結果,都將始終是返回的值。 還是在這種情況下可能是其他原因?
我需要驗證嗎? 我覺得我這樣做是因為我想驗證是否確實調用了 personRepository.count() 。 或者當我也有 assertEquals() 時那是多余的嗎?
我需要 assertEquals 和驗證嗎?
最后,我這樣做對嗎:)
謝謝
為了:
是否需要assertEquals()
:取決於。 返回之前, personService
中personRepository.count()
的結果是否有任何改變的可能? 如果答案是“絕對不是”,那么您可能不需要assertEquals()
-但是,如果有可能出現問題,則assertEquals()
將確保沒有錯。
您是否需要verify()
:這取決於。 是否有可能沒有調用personRepository.count()
? 還是它被多次調用verify()
默認情況下verify()
期望其參數被精確調用一次)? 如果不是,那么您可能不需要它。
您是否需要兩者:它取決於(注意到一種模式?)。 見上文:他們做了不同的事情。 在很多情況下,您都希望同時檢查這兩種情況:1.返回正確的結果,並且2.通過執行您希望做的事情來返回結果。
您做對了嗎:好吧...這取決於。 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()
因為突然之間,發生了很多事情,即使有些事情出了嚴重問題,也可能會混淆其中的一些(即隨機數)以確保功能正常。
是的,您做對了。
您正在將模擬存儲庫注入到真實服務中,然后測試該服務。 當涉及到服務中的業務邏輯時,可能會發生任何事情。 這就是為什么像您所做的那樣,用已知的輸入和已知的輸出來驗證代碼很重要。
給定存儲庫的響應,您正在檢查業務邏輯的結果。 這個特定的代碼非常簡單,但是可以想象一下,業務邏輯是在提供平均值還是總和,而不僅僅是從存儲庫提供的相同值。
3.verify和assertEquals正在測試不同的東西。 驗證檢查您的存儲庫方法是否被調用,斷言檢查服務是否以正確的值響應。 想象一下,您的服務方法有一個硬編碼的return 2L
。 assertEquals將通過,但驗證將失敗。
是的,您做對了。 您要測試的內容與您要測試的原因有關。 是否需要特定的斷言或驗證通常取決於具體情況。 在這種情況下,測試存儲庫方法返回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..)) 的預期結果,都將始終是返回的值。
所以你做得對。
4.
最后,我這樣做對嗎:)
我認為這是一個很好的典型白盒測試:)
參考:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.