mockito入门_Mockito入门
mockito入門
本文是我們名為“ 用Mockito測試 ”的學院課程的一部分。
在本課程中,您將深入了解Mockito的魔力。 您將了解有關“模擬”,“間諜”和“部分模擬”的信息,以及它們相應的存根行為。 您還將看到使用測試雙打和對象匹配器進行驗證的過程。 最后,討論了使用Mockito的測試驅動開發(TDD),以了解該庫如何適合TDD的概念。 在這里查看 !
目錄
1.為什么要模擬? 2. Mockito框架簡介在本教程中,我們將研究Mockito Mocking Framework,并通過將其添加到類路徑中來準備一個Eclipse項目來使用它。
1.為什么要模擬?
我們編寫的所有代碼都有一個相互依賴的網絡,它可以調用其他幾個類的方法,而這些類又可以調用其他方法。 確實,這就是面向對象編程的意圖和力量。 通常在編寫功能代碼的同時,我們還將以自動化單元測試的形式編寫測試代碼。 我們使用這些單元測試來驗證代碼的行為,以確保其行為符合我們的預期。
當我們對代碼進行單元測試時,我們希望對其進行隔離測試,并希望對其進行快速測試。 為了進行單元測試,我們只關心在當前測試的類中驗證自己的代碼。 通常,我們還希望非常定期地執行單元測試,重構時以及在持續集成環境中工作時,每小時可能要執行多次。
這是我們所有相互依存成為問題的時候。 我們可能最終在另一個類中執行代碼,該類中的錯誤導致導致單元測試失敗。 想象一下我們用來從數據庫中讀取用戶詳細信息的類,如果要運行單元測試時沒有數據庫,會發生什么? 想象一下,一個調用多個遠程Web服務的類,如果它們出現故障或需要很長時間響應怎么辦? 我們的單元測試可能由于我們的依賴關系而失敗,而不是因為我們的代碼行為出現問題。 這是不希望的。
除此之外,強制執行想要確保代碼正確處理的特定事件或錯誤條件可能非常困難。 如果我們要測試某個反序列化對象的類如何正確處理可能的ObjectStreamException怎么辦? 如果我們要測試協作者的所有邊界返回值怎么辦? 確保將某些計算值正確傳遞給協作者該怎么辦? 如果可能的話,復制我們的測試條件可能需要花費大量的代碼和較長的時間。
如果使用模擬,所有這些問題都會消失。 嘲笑就像是我們與之合作的類的替代品一樣,它們取代了他們的位置,并按照我們告訴他們的行為去做。 嘲弄讓我們假裝我們真正的合作者在那里,即使他們不在。 更重要的是,可以對模擬程序進行編程,以返回我們想要的任何值并確認將任何值傳遞給它們。 模擬程序立即執行,不需要任何外部資源。 假人會返回我們告訴他們的東西,拋出我們想讓他們拋出的任何異常,并將按需一遍又一遍地執行這些操作。 他們讓我們僅測試我們自己代碼的行為,以確保我們的類能夠正常工作,而不管其協作者的行為如何。
有幾種可用于Java的模擬框架,每種都有各自的語法,各自的優勢,各自的劣勢。 在本教程中,我們將使用Mockito框架,它是最流行的可用模擬框架之一。
2. Mockito框架簡介
Mockito是一個Mocking框架,可以很容易地為要與您的被測類進行交互的類和接口創建模擬。 Mockito提供了一個非常簡單的API,用于創建模擬并分配其行為。 它使您可以非??焖俚刂付A期的行為并驗證與模擬的交互。
Mockito本質上具有兩個階段,其中一個或兩個階段都作為單元測試的一部分執行:
- 存根
- 驗證
存根是指定模擬行為的過程。 這就是我們告訴Mockito與模擬互動時想要發生的事情的方式。 存根使我們能夠解決我們在第一部分中概述的一些問題–它使為測試創建所有可能的條件變得簡單。 它讓我們控制了模擬的響應,包括強迫它們返回我們想要的任何值,或者拋出我們想要的任何異常。 它使我們可以在不同條件下編寫不同的行為。 存根使我們可以精確控制模擬將執行的操作。
驗證是驗證與我們的模擬互動的過程。 它使我們能夠確定模擬的調用方式以及調用的次數。 它使我們可以查看模擬的參數,以確保它們符合預期。 驗證使我們能夠解決第一節中提到的其他問題–它使我們確保將我們期望的值準確地傳遞給我們的合作者,并且不會發生意外情況。 驗證使我們能夠準確確定模擬發生了什么。
通過將這兩個簡單的階段聯系在一起,我們可以構建極其靈活且功能強大的單元測試,使用非常簡單的Mockito API編碼復雜的模擬行為和復雜的模擬交互驗證。
Mockito確實有一些限制,包括
- 你不能嘲笑期末班
- 您不能模擬靜態方法
- 您不能模擬最終方法
- 您不能模擬equals()或hashCode()
存根的快速示例
想象一下,您正在編寫一個調用物理溫度傳感器API的類。 您要調用double getDegreesC()方法并基于從傳感器返回的值返回以下字符串之一:“ Hot”,“ Mild”,“ Cold”。 至少可以說,要使單元測試控制房間的環境溫度以測試功能非常困難。 但是,如果我們使用Mockito來創建替代傳感器的模擬物,該怎么辦?
現在我們可以在單元測試中編寫如下代碼:
when(sensor.getDegreesC()).thenReturn(15.0);這告訴Mockito,當模擬傳感器收到對getDegreesC()的調用時,它應該然后返回值15.0。
快速驗證示例
假設您有一個類進行一些計算,并負責在觀察者完成計算后通知觀察者。 您想確保在執行方法的過程中一次調用了觀察者的notify()方法。 您可以在觀察器中設置一些布爾值,然后從單元測試中進行檢查,但這意味著更改一些生產代碼,甚至您可能都不擁有這些代碼。 Mockito怎么樣,如果觀察者是模擬的呢?
現在我們可以在單元測試中編寫如下代碼:
verify(observer).notify();這告訴Mockito必須僅一次調用一次notify()方法,否則單元測試應該失敗。
3.混合一個Mockito
現在,我們已經了解了一些有關框架的知識,讓我們在項目中使用它。
如果使用Maven,則將Mockito添加到項目中就像添加以下依賴項一樣簡單:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId><version>1.9.5</version><scope>test</scope></dependency>如果您使用Gradle,則只需添加以下內容
dependencies {testCompile "org.mockito:mockito-all:1.9.5" }要將舊版Mockito添加到Eclipse項目的類路徑中,請從Mockito下載頁面中獲取最新的jar( 取名為 mockito-all-1.9.5.jar)并將其下載到硬盤上。
右鍵單擊您的eclipse項目,然后選擇“屬性”,然后在左窗格中選擇“ Java Build Path”,然后在右側選擇“ Libraries”。
在“庫”選項卡上,單擊“添加外部Jar”按鈕,然后導航到您先前下載的模擬所有jar。 選擇罐子,它現在已添加到您的項目中并可供使用。
在撰寫本文時,Mockito的最新版本是1.9.5,但是在將其添加到項目之前,應檢查更新。
4.將Mockito與JUnit一起使用
要將Mockito集成到您的JUnit測試類中,可以使用提供的Test Runner MockitoJUnitRunner 。 只需使用以下注釋您的測試課:
@RunWith(MockitoJUnitRunner.class)這告訴Mockito在測試類中接受所有帶注釋的模擬,并對其進行初始化以進行模擬。 然后,您可以簡單地使用@Mock注釋任何實例變量以將其用作模擬。 請注意,您應該導入org.mockito.Mock而不是org.mockito.mockitoannotations.Mock (已棄用)。
與所有示例一樣,我們將創建一個新的Test類,并在其中使用Mockito模擬java.util.List :
import java.util.List; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner;@RunWith(MockitoJUnitRunner.class) public class MyTest {@Mockprivate List<String> mockList;}@Mock注釋告訴Mockito模擬mockList將被視為模擬,而@RunWith(MockitoJUnitRunner.class)告訴Mockito遍歷MyTest所有帶有@Mock注釋的成員,并將其初始化以進行模擬。 您不必將任何新實例分配給嘲笑列表,這是由Mockito在后臺完成的。 通過上面的簡單代碼,mockList準備好用作模擬了。
嘗試添加以下導入:
import static org.junit.Assert.*; import static org.mockito.Mockito.*; import org.junit.Test;然后是以下簡單的測試用例:
@Testpublic void test() {String expected = "Hello, World!";when(mockList.get(0)).thenReturn(expected);String actual = mockList.get(0);assertEquals(expected, actual);System.out.println(actual);}在這里,我們看到了我們的期望-我們有一個字符串"Hello, World!" 然后繼續對模擬列表的List.get()方法進行存根, List.get()在請求列表的第一個元素時返回期望的String。
然后,我們調用mockList.get(0)以獲取測試的實際值,并斷言我們的實際值等于我們的預期值,然后將其輸出到控制臺以進行良好測量。
我們根本沒有創建真實列表,也沒有插入“ Hello,World!” 進入列表。 它只是一個模擬列表,它具有或知道的唯一功能是輸入為0的get()方法。
嘗試更改String actual = mockList.get(0); 到String actual = mockList.get(1); 并運行測試。 您將看到actual值現在為空。 原因是我們唯一保留的功能是使用輸入0調用.get()– Mockito不知道如何使用輸入1進行操作,因此它僅返回null。 實際上,我們調用List的任何其他方法都將返回null,而任何不返回任何值的方法將有效地充當no-op。 這是一個功能強大的控件,在幾行代碼中,我們創建了List的實現,該實現恰好在每次調用它時都可以實現我們想要的功能。
5. Mockito最佳做法
Mockito通常鼓勵在單元測試和設計中采用標準的最佳實踐,即:
- Mockito沒有模擬靜態方法的規定,因為Mockito鼓勵面向對象的設計和對過程代碼的依賴注入。
- Mockito沒有提供模擬私有方法的規定,因為公共方法應該是黑盒,并且從測試私有方法的角度來看不存在。
- Mockito打包并鼓勵使用Hamcrest Matchers,這將在后續教程中介紹。
- Mockito鼓勵遵守Demeter法則,而不鼓勵嘲笑鏈式方法。
- 您不應存根或驗證在不同線程之間共享的模擬。 但是,您可以調用共享模擬的方法。
- 您無法驗證模擬的toString()方法,原因是測試環境本身可能會調用它,因此無法進行驗證。
- 如果您的測試用例使用了“當時給定”表示法,則可以使用org.mockito.BDDMockito的存根方法,以便when(mock.method()).thenReturn(something)成為given(mock.method()).willReturn(something)因為它將以您的測試格式很好地閱讀。
- 可以在不使用Mockito批注的情況下使用Mockito,但是使用批注更加容易和整潔,這就是我們在這些教程中將要做的。
- 如果您的測試要求您出于測試目的修改類的特定方法的行為,則可以“監視”任何類,包括被測類。 Mockito明確建議僅在偶爾使用間諜的情況下使用間諜,例如在處理遺留代碼的情況下。 這將在以后的教程中介紹。
- 如果對間諜方法的實際調用可能會產生錯誤條件,或者由于某些其他原因而無法調用,則Mockito建議使用do *系列方法進行存根。 這將在以后的教程中介紹。
- Mockito將允許您使用參數匹配器代替實際參數,但有一個限制:如果一個參數使用匹配器,則所有參數都必須使用匹配器。 參數匹配器將在以后的教程中介紹,但應謹慎使用。
- Mockito提供了verifyNoMoreInteractions()方法來驗證特定的模擬沒有更多的交互,但建議僅在適當的情況下謹慎使用。
- Mockito提供了Answer接口以允許使用回調進行存根,但建議不要使用它,并鼓勵您使用thenReturn()和doThrow()方法進行簡單的存根。 我們將在以后的教程中介紹答案。
- 如果使用ArgumentCaptor進行參數驗證,則應僅在驗證階段而不是存根階段使用它。 ArgumentCaptor將在以后的教程中介紹。
- Mockito建議非常小心地使用Partial Mocks,主要是在處理遺留代碼時。 設計良好的代碼不應要求使用部分模擬。
- Mockito提供了一個reset()方法,用于在測試方法的中間重置模擬,但是建議您不要使用它,因為它是一種代碼氣味,可能會使您的測試過長且過于復雜。
有更多的功能和做法,但是這些是Mockito告訴您要注意的主要功能和做法。 我們將在接下來的教程中介紹以上所有內容,并進行更深入的介紹。
翻譯自: https://www.javacodegeeks.com/2015/11/getting-started-with-mockito.html
mockito入門
總結
以上是生活随笔為你收集整理的mockito入门_Mockito入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cad数数快捷键(cad计数快捷键)
- 下一篇: 逃跑吧少年电脑怎么下(逃跑吧少年电脑下载