日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Mockito的使用(一)——@InjectMocks、@Spy、@Mock

發布時間:2025/3/19 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Mockito的使用(一)——@InjectMocks、@Spy、@Mock 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

GItHub上有相應的翻譯好的中文文檔: https://github.com/hehonghui/mockito-doc-zh/blob/master/README.md#0

搭建Mockito測試環境

前些文章已有過描述,重溫一下.

dependencies {// ... more entriestestCompile 'junit:junit:4.12'// required if you want to use Mockito for unit teststestCompile 'org.mockito:mockito-core:2.7.22'// required if you want to use Mockito for Android testsandroidTestCompile 'org.mockito:mockito-android:2.7.22' }

使用Mockito創建mock對象

Mockito提供幾種創建mock對象的方法:

  • 使用靜態方法 mock()
  • 使用注解 @Mock 標注

如果使用@Mock注解, 必須去觸發所標注對象的創建. 可以使用 MockitoRule來實現. 它調用了靜態方法MockitoAnnotations.initMocks(this) 去初始化這個被注解標注的字段.或者也可以使用@RunWith(MockitoJUnitRunner.class).

JUnit Rule請回顧之前文章

具體的用法可以參照下面示例:

import static org.mockito.Mockito.*; public class ClassToTestTest {@MockMyDatabase databaseMock;//①@Rulepublic MockitoRule mockitoRule = MockitoJUnit.rule();//②@Testpublic void query() throws Exception {ClassToTest t = new ClassToTest(databaseMock);//③boolean check = t.query("* from t");//④assertTrue(check);//⑤verify(databaseMock).query("* from t");//⑥} }
  • 通知Mockito模擬databaseMock實例
  • 通知Mockito創建被 @Mock 注解標注 的模擬對象(本例中就是databaseMock)
  • 用上一步創建的模擬對象去實例化測試類
  • 執行測試代碼
  • 斷言返回值為true
  • 驗證MyDatabase中的query方法被調用
  • 再次重申一下靜態導入的重要性,使用靜態導入可以非常好的提高代碼的可讀性,你值得擁有

    配置模擬對象

    Mockito可以通過自然的API來實現模擬對象的返回值.沒有指定的方法調用返回空值:

    • object返回null
    • 數值類型返回0
    • boolean返回false
    • 集合將返回空集合
    • ……

    以下的斷言語句僅用于演示目的. 真正的測試應該用模擬對象來測試另一些功能.

    “when thenReturn”和”when thenThrow”

    模擬對象可以根據傳入方法中的參數來返回不同的值, when(….).thenReturn(….)方法是用來根據特定的參數來返回特定的值.

    我們也可以使用像anyString或者anyInt 這樣的方法來定義某個依賴數據類型的方法返回特定的值.

    如果指定了多個值,他們將按照順序返回多個值.

    請參照下方示例:

    @Testpublic void test1() {// 創建mock對象MyClass test = mock(MyClass.class);// 定義getUniqueId()方法返回特定的值when(test.getUniqueId()).thenReturn(43);// 執行測試assertEquals(test.getUniqueId(), 43);}// 返回多個值的示例@Testpublic void testMoreThanOneReturnValue() {Iterator<String> i= mock(Iterator.class);when(i.next()).thenReturn("Mockito").thenReturn("rocks");String result= i.next()+" "+i.next();//assertassertEquals("Mockito rocks", result);}// 如何根據輸入來返回值@Testpublic void testReturnValueDependentOnMethodParameter() {Comparable<String> c= mock(Comparable.class);when(c.compareTo("Mockito")).thenReturn(1);when(c.compareTo("Eclipse")).thenReturn(2);//assertassertEquals(1, c.compareTo("Mockito"));}// 返回值獨立于輸入值@Testpublic void testReturnValueInDependentOnMethodParameter() {Comparable<Integer> c= mock(Comparable.class);when(c.compareTo(anyInt())).thenReturn(-1);//assertassertEquals(-1, c.compareTo(9));}// 根據提供參數的類型返回特定的值@Testpublic void testReturnValueInDependentOnMethodParameter2() {Comparable<Todo> c= mock(Comparable.class);when(c.compareTo(isA(Todo.class))).thenReturn(0);//assertassertEquals(0, c.compareTo(new Todo(1)));}

    when(….).thenReturn(….)也可以用來拋出異常

    Properties properties = mock(Properties.class); when(properties.get("Anddroid")).thenThrow(new IllegalArgumentException(...)); try {properties.get("Anddroid");fail("Anddroid is misspelled"); } catch (IllegalArgumentException ex) {// good! }

    “doReturn when” 和 “doThrow when”

    doReturn(…).when(…)的方法調用和when(….).thenReturn(….)類似.對于調用過程中拋出的異常非常有用.而doThrow則也是它的一個變體.

    具體在Spy中使用.

    使用Spy包裝Java對象

    可以使用@Spy注解 或者 spy() 方法來包裝一個真實的對象. 除非有特殊的指定,否則每次調用都會委托給該對象.

    示例如下:

    public class SpyTest {@Testpublic void testLinkedListSpyWrong() {// 讓我們來模擬一個LinkedListList<String> list = new LinkedList<>();List<String> spy = spy(list);// spy.get(0)將會調用真實的方法// 將會拋出 IndexOutOfBoundsException (list是空的)when(spy.get(0)).thenReturn("foo");assertEquals("foo", spy.get(0));}@Testpublic void testLinkedListSpyCorrect() {// 讓我們來模擬一個LinkedListList<String> list = new LinkedList<>();List<String> spy = spy(list);// 必須使用doReturn來插樁doReturn("foo").when(spy).get(0);assertEquals("foo", spy.get(0));} }

    注: 在使用Spy包裝真實對象時使用when(….).thenReturn(….)將無效,必須使用 doReturn(…).when(…)來進行插樁.

    驗證模擬對象的調用

    Mockito將會追蹤所有方法的調用和傳入模擬對象的參數.你可以在模擬對象上使用verify()方法驗證指定的條件是否滿足.例如,你可以驗證是否使用某些參數調用了方法.這種測試稱為行為測試.行為測試并不能檢查方法調用的結果,但是它可以驗證一個方法是否使用正確的參數被調用.

    示例如下:

    public class VerifyTest {@Testpublic void testVerify() {// 創建模擬對象MyClass test = Mockito.mock(MyClass.class);when(test.getUniqueId()).thenReturn(43);// 調用模擬對象的方法testing,并傳入參數12test.testing(12);test.getUniqueId();test.getUniqueId();// 檢查方法testing是否使用參數//12調用了verify(test).testing(ArgumentMatchers.eq(12));// 驗證調用兩次getUniqueIdverify(test, times(2)).getUniqueId();// 也可以使用下面的方法來替代調用的次數verify(test, never()).someMethod("never called 從來沒有調用");verify(test, atLeastOnce()).someMethod("called at least once 至少被調用一次");verify(test, atLeast(2)).someMethod("called at least twice 至少被調用5次");verify(test, times(5)).someMethod("called five times 被調用5次");verify(test, atMost(3)).someMethod("called at most 3 times 至多被調用3次");//下面的方法用來檢查是否所有的用例都涵蓋了,如果沒有將測試失敗//放在所有的測試后面verifyNoMoreInteractions(test);} }

    如果你并不關心輸入值,可以使用anyXXX()方法,例如,anyInt(), anyString()或者any(Your.class)等等方法.

    @InjectMocks進行依賴注入

    我們可以使用@InjectMocks注解根據類型對構造方法,普通方法和字段進行依賴注入.

    假設你有下面的類.

    public class ArticleManager {private User user;private ArticleDatabase database;public ArticleManager(User user, ArticleDatabase database) {super();this.user = user;this.database = database;}public void initialize() {database.addListener(new ArticleListener());} }

    這個類可以通過Mockito構建,并且它的依賴關系可以通過模擬對象來實現,下面的代碼就演示這一關系:

    @RunWith(MockitoJUnitRunner.class) public class ArticleManagerTest {@MockArticleCalculator calculator;@MockArticleDatabase database;@MockUser user;@InjectMocksprivate ArticleManager manager; //①@Testpublic void shouldDoSomething() {//使用了一個ArticleListener實例調用了addListenermanager.initialize();// 驗證database調用使用了ArticleListener類型的參數調用了addListenerverify(database).addListener(any(ArticleListener.class));}}
  • 這一步創建了一個ArticleManager實例并注入到了模擬對象中.
  • Mockito可以通過構造方法注入,setter注入和屬性注入的順序來注入模擬對象(mock).因此如果ArticleManager的構造方法只包含User, 并且這兩個字段都有setter,那這種情況下只有User的模擬對象會被注入.

    捕獲參數

    ArgumentCaptor類允許在驗證的時候可以訪問到方法的調用參數,并用于測試.

    下面的示例需要添加依賴: https://mvnrepository.com/artifact/org.hamcrest/hamcrest-library

    public class MockitoTests {@Rulepublic MockitoRule rule = MockitoJUnit.rule();@Captorprivate ArgumentCaptor<List<String>> captor;@Testpublic final void shouldContainCertainListItem() {List<String> asList = Arrays.asList("someElement_test", "someElement");final List<String> mockedList = mock(List.class);mockedList.addAll(asList);verify(mockedList).addAll(captor.capture());final List<String> capturedArgument = captor.getValue();assertThat(capturedArgument, hasItem("someElement"));} }

    Answer的使用

    在寫測試用例時針對復雜的方法結果往往會使用Answer.雖然使用thenReturn可以每次返回一個預定義的值,但是通過answers可以讓你的插樁方法(stubbed method)根據參數計算出結果.

    例如,下面是使用Answer實現插樁方法返回第一個參數值的示例:

    //假設存在這么一個類(僅為測試,毫無意義) class TestObj {public String add(String firstArg, String lastArg) {return "";} } //... @Test public final void answerTest() {TestObj testObj = mock(TestObj.class);// with doAnswer():doAnswer(returnsFirstArg()).when(testObj).add(anyString(), anyString());// with thenAnswer():when(testObj.add(anyString(), anyString())).thenAnswer(returnsFirstArg());// with then() alias:when(testObj.add(anyString(), anyString())).then(returnsFirstArg());//測試打印結果System.out.println(testObj.add("FirstArg", "LastArg")); }

    打印結果:

    FirstArg

    有的時候你可能需要一個回調作為方法參數:

    @Test public final void callbackTest() {ApiService service = mock(ApiService.class);when(service.login(any(Callback.class))).thenAnswer(new Answer<Object>() {@Overridepublic Object answer(InvocationOnMock invocation) throws Throwable {Callback callback = invocation.getArgument(0);callback.notify("Success");return "Test Result";}});String result = service.login(new Callback() {@Overridepublic void notify(String notify) {System.out.println(notify);}});System.out.println(result); }

    打印結果:

    Success Test Result

    甚至可以模擬一個持久服務,比如Dao, 但是如果Answers非常復雜應該考慮創建一個fake 類而不是mock.

    @Test public final void TestDao() {List<User> userMap = new ArrayList<>();UserDao dao = mock(UserDao.class);when(dao.save(any(User.class))).thenAnswer(i -> {User user = i.getArgument(0);userMap.add(user.getId(), user);return null;});when(dao.find(any(Integer.class))).thenAnswer(i -> {int id = i.getArgument(0);return userMap.get(id);}); }

    模擬 final class

    自從Mockito v2 以來可以模擬final class, 這個功能目前正在優化階段,并且默認是停用的.要想激活final class,在src/test/resources/mockito-extensions/或者src/mockito-extensions/目錄創建名為org.mockito.plugins.MockMaker的文件,并在文件中添加一行:

    mock-maker-inline
    • 1

    如圖所示:

    測試代碼:

    final class FinalClass {public final String finalMethod() { return "something"; } }@Test public final void mockFinalClassTest() {FinalClass instance = new FinalClass();FinalClass mock = mock(FinalClass.class);when(mock.finalMethod()).thenReturn("that other thing");assertNotEquals(mock.finalMethod(), instance.finalMethod()); }

    當然,如果你不這么做,編譯器將會拋出異常:

    Mockito cannot mock/spy because : – final class

    Mockito一些重要的Api暫時就介紹到這里, 更多Api請移步: https://github.com/hehonghui/mockito-doc-zh/blob/master/README.md#0

    總結

    以上是生活随笔為你收集整理的Mockito的使用(一)——@InjectMocks、@Spy、@Mock的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 欧美一区二区公司 | 一区二区三区视频在线播放 | 人人干人人艹 | 陪读偷伦初尝小说 | 在线永久看片免费的视频 | av一区二区三区免费观看 | 四虎精品在线播放 | 欧美交 | 日日爽夜夜爽 | 亚洲日本护士毛茸茸 | 亚洲精品一区二区三区蜜臀 | 十八禁毛片 | 国产做爰高潮呻吟视频 | 一区二区三区免费网站 | 国产www精品| 嫩草视频在线观看免费 | 久久精品国产99精品国产亚洲性色 | 日本特黄成人 | 少妇2做爰bd在线意大利堕落 | 国产精品久久免费视频 | 熟女高潮一区二区三区 | 久久精品久久久精品美女 | 国产成人三级在线观看 | 欧美不卡网 | 视频二区在线观看 | 成年网站免费观看 | 欧美亚洲一区二区三区四区 | 日韩一区在线播放 | 毛片在线免费观看视频 | 欧美日韩亚洲综合 | 人妻熟女一区二区三区app下载 | 欧美一区二区三区在线 | 亚洲特黄| 欧美国产专区 | 国产精品国产三级国产普通话对白 | 欧洲一区二区在线观看 | 99久久久无码国产精品性青椒 | 国产我不卡 | 国产一区二区久久精品 | 国产在线视频导航 | 国产精品传媒 | 视频免费在线观看 | 国产一卡二卡三卡四卡 | 久久久久久久极品 | 中国女人内96xxxxx | 疯狂做爰的爽文多肉小说王爷 | 久操中文| 欧美成年人视频在线观看 | 国产传媒第一页 | 国产视频久久久久久久 | 国产精品av在线播放 | 插插插av| 农村偷人一级超爽毛片 | 激情综合区 | 美女的诞生免费观看在线高清 | 人妻少妇被猛烈进入中文字幕 | 波多野结衣中文字幕一区二区 | 婷婷久久久久久 | www.亚洲色图.com | 爆操少妇 | 亚洲成人自拍偷拍 | 亚洲鲁鲁| 男女福利视频 | 国产一级在线 | 51啪影院 | 久久免费公开视频 | 老王66福利网 | 人妻偷人精品一区二区三区 | 国产精品主播一区二区 | 艳妇臀荡乳欲伦交换在线看 | 欧美一级专区 | 国产日产亚洲精品 | 99福利视频导航 | 性生活免费网站 | 宿舍女女闺蜜调教羞辱 | 一区精品二区国产 | 日韩久久av| 精品日韩av | 亚洲av无码国产精品久久不卡 | 岛国精品一区二区 | 丨国产丨调教丨91丨 | 青青艹在线观看 | 搞黄视频在线观看 | 精人妻无码一区二区三区 | 亚洲第5页 | 亚洲狼人在线 | 黄色小说视频网站 | 国产欧美日本 | 亚洲综合图区 | 蜜桃精品在线观看 | 好紧好爽再浪一点视频 | av免费不卡 | 干美女少妇 | 麻豆伊甸园 | 欧美日p视频 | 蜜桃tv在线观看 | av男人网| 手机看片福利在线 | 亚洲一区你懂的 |