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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Mockito:一个强大的用于Java开发的模拟测试框架

發布時間:2025/3/21 java 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Mockito:一个强大的用于Java开发的模拟测试框架 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

介紹


  本文將介紹模擬測試框架Mockito的一些基礎概念, 介紹該框架的優點,講解應用Mockito的Java示例。


模擬(Mock)的概念?


  在軟件開發的世界之外, "mock"一詞是指模仿或者效仿。因此可以將“mock”理解為一個替身,替代者。在軟件開發中提及"mock",通常理解為模擬對象或者fake。

  譯者注:mock等多代表的是對被模擬對象的抽象類,你可以把fake理解為mock的實例。不知道這樣說準不準確:)

  Fake通常被用作被測類依賴關系的替代者.。

名詞定義??
依賴關系?– 依賴關系是指在應用程序中一個類基于另一個類來執行其預定的功能。依賴關系通常都存在于所依賴的類的實例變量中。
?
被測類?– 在編寫單元測試的時候,“單元”一詞通常代表一個單獨的類及為其編寫的測試代碼。被測類指的就是其中被測試的類。

為什么需要模擬??

  在我們一開始學編程時,我們所寫的對象通常都是獨立的。hello world之類的類并不依賴其他的類(System.out除外),也不會操作別的類。但實際上軟件中是充滿依賴關系的。我們會基于service類寫操作類,而service類又是基于數據訪問類(DAOs)的,依次下去。

圖1 類的依賴關系

  單元測試的思路就是我們想在不涉及依賴關系的情況下測試代碼。這種測試可以讓你無視代碼的依賴關系去測試代碼的有效性。核心思想就是如果代碼按設計正常工作,并且依賴關系也正常,那么他們應該會同時工作正常。

  下面的代碼就是這樣的例子:

[java]?view plaincopy
  • import?java.util.ArrayList;??
  • public?class?Counter?{??
  • ?????public?Counter()?{??
  • ?????}??
  • ?????public?int?count(ArrayList?items)?{??
  • ??????????int?results?=?0;??
  • ??????????for(Object?curItem?:?items)?{??
  • ???????????????results?++;??
  • ??????????}??
  • ??????????return?results;??
  • ?????}??
  • }???
  •   如你所見,上面的例子十分簡單,但它闡明了要點。當你想要測試count方法時,你會針對count方法本身如何工作去寫測試代碼。你不會去測試ArrayList是否正常工作,因為你默認它已經被測過并且工作正常。你唯一的目標就是測試對ArrayList的使用。
      模擬對象的概念就是我們想要創建一個可以替代實際對象的對象。這個模擬對象要可以通過特定參數調用特定的方法,并且能返回預期結果。


    模擬有哪些關鍵點?


      在談到模擬時,你只需關心三樣東西:設置測試數據,設定預期結果,驗證結果。一些單元測試方案根本就不涉及這些,有的只涉及設置測試數據,有的只涉及設定預期結果和驗證。

    Stubbing?(樁)

      Stubbing就是告訴fake當與之交互時執行何種行為過程。通常它可以用來提供那些測試所需的公共屬性(像getters和setters)和公共方法。

      當談到stubbing方法,通常你有一系列的選擇。或許你希望返回一個特殊的值,拋出一個錯誤或者觸發一個事件,此外,你可能希望指出方法被調用時的不同行為(即通過傳遞匹配的類型或者參數給方法)。

      這咋一聽起來工作量很大,但通常并非這樣。許多mocking框架的一個重要功能就是你不需要提供stub 的實體方法,也不用在執行測試期間stub那些未被調用的方法或者未使用的屬性。

    設置預期

      Fake的一個關鍵的特性就是當你用它進行模擬測試時你能夠告訴它你預期的結果。例如,你可以要求一個特定的函數被準確的調用3次,或不被調用,或調用至少兩次但不超過5次,或者需要滿足特定類型的參數、特定值和以上任意的組合的調用。可能性是無窮的。

      通過設定預期結果告訴fake你期望發生的事情。因為它是一個模擬測試,所以實際上什么也沒發生。但是,對于被測試的類來說,它并無法區分這種情況。所以fake能夠調用函數并讓它做它該做的。

      值得注意的是,大多數模擬框架除了可以創建接口的模擬測試外,還可以創建公有類的模擬測試。

    驗證預期結果

      設置預期和驗證預期是同時進行的。設置預期在調用測試類的函數之前完成,驗證預期則在它之后。所以,首先你設定好預期結果,然后去驗證你的預期結果是否正確。

      在一個單元測試中,如果你設定的預期沒有得到滿足,那么這個單元測試就是失敗了。例如,你設置預期結果是?ILoginService.login函數必須用特定的用戶名和密碼被調用一次,但是在測試中它并沒有被調用,這個fake沒被驗證,所以測試失敗。


    模擬的好處是什么??

    ???提前創建測試; TDD(測試驅動開發)??

      這是個最大的好處吧。如果你創建了一個Mock那么你就可以在service接口創建之前寫Service Tests了,這樣你就能在開發過程中把測試添加到你的自動化測試環境中了。換句話說,模擬使你能夠使用測試驅動開發。?

    ???團隊可以并行工作?

      這類似于上面的那點;為不存在的代碼創建測試。但前面講的是開發人員編寫測試程序,這里說的是測試團隊來創建。當還沒有任何東西要測的時候測試團隊如何來創建測試呢?模擬并針對模擬測試!這意味著當service借口需要測試時,實際上QA團隊已經有了一套完整的測試組件;沒有出現一個團隊等待另一個團隊完成的情況。這使得模擬的效益型尤為突出了。?

    ???你可以創建一個驗證或者演示程序。?

      由于Mocks非常高效,Mocks可以用來創建一個概念證明,作為一個示意圖,或者作為一個你正考慮構建項目的演示程序。這為你決定項目接下來是否要進行提供了有力的基礎,但最重要的還是提供了實際的設計決策。?

    ??為無法訪問的資源編寫測試?

      這個好處不屬于實際效益的一種,而是作為一個必要時的“救生圈”。有沒有遇到這樣的情況?當你想要測試一個service接口,但service需要經過防火墻訪問,防火墻不能為你打開或者你需要認證才能訪問。遇到這樣情況時,你可以在你能訪問的地方使用MockService替代,這就是一個“救生圈”功能。?

    ??Mock?可以分發給用戶?

    ????? 在有些情況下,某種原因你需要允許一些外部來源訪問你的測試系統,像合作伙伴或者客戶。這些原因導致別人也可以訪問你的敏感信息,而你或許只是想允許訪問部分測試環境。在這種情況下,如何向合作伙伴或者客戶提供一個測試系統來開發或者做測試呢?最簡單的就是提供一個mock,無論是來自于你的網絡或者客戶的網絡。soapUI mock非常容易配置,他可以運行在soapUI或者作為一個war包發布到你的java服務器里面。?

    ??隔離系統?

    ????? 有時,你希望在沒有系統其他部分的影響下測試系統單獨的一部分。由于其他系統部分會給測試數據造成干擾,影響根據數據收集得到的測試結論。使用mock你可以移除掉除了需要測試部分的系統依賴的模擬。當隔離這些mocks后,mocks就變得非常簡單可靠,快速可預見。這為你提供了一個移除了隨機行為,有重復模式并且可以監控特殊系統的測試環境。?


    Mockito 框架


      Mockito 是一個基于MIT協議的開源java測試框架。?
      Mockito區別于其他模擬框架的地方主要是允許開發者在沒有建立“預期”時驗證被測系統的行為。對mock對象的一個批評是測試代碼與被測系統高度耦合,由于Mockito試圖通過移除“期望規范”來去除expect-run-verify模式(期望--運行--驗證模式),因此使耦合度降低到最低。這樣的突出特性簡化了測試代碼,使它更容易閱讀和修改了。

    你可以驗證交互:

    [java]?view plaincopy
  • //?模擬的創建,對接口進行模擬??
  • List?mockedList?=?mock(List.class);??
  • //?使用模擬對象??
  • mockedList.add("one");??
  • mockedList.clear();??
  • //?選擇性地和顯式地驗證??
  • verify(mockedList).add("one");??
  • verify(mockedList).clear();????
  • 或者存根方法調用:

    [java]?view plaincopy
  • //?你不僅可以模擬接口,任何具體類都行??
  • LinkedList?mockedList?=?mock(LinkedList.class);??
  • //?執行前準備測試數據??
  • when(mockedList.get(0)).thenReturn("first");??
  • //?接著打印"first"??
  • System.out.println(mockedList.get(0));??
  • //?因為get(999)未對準備數據,所以下面將打印"null".??
  • System.out.println(mockedList.get(999));???

  • 一個使用Mockito框架的簡單Java代碼示例



    圖2 不使用Mock框架


    圖3 使用Mockito框架

    步驟 1: ?在IDE中創建一個普通的Java項目?

      在Eclipse、NetBeans或IntelliJ IDEA中創建一個普通的Java項目。

    步驟 2: ?添加java源碼 ?

      類Person.java:

    [java]?view plaincopy
  • package?mockitodemo;??
  • ??
  • public?class?Person??
  • {??
  • ????private?final?Integer?personID;??
  • ????private?final?String?personName;??
  • ????public?Person(?Integer?personID,?String?personName?)??
  • ????{??
  • ????????this.personID?=?personID;??
  • ????????this.personName?=?personName;??
  • ????}??
  • ????public?Integer?getPersonID()??
  • ????{??
  • ????????return?personID;??
  • ????}??
  • ????public?String?getPersonName()??
  • ????{??
  • ????????return?personName;??
  • ????}??
  • }???
  •   接口PersonDAO.java
    [java]?view plaincopy
  • package?mockitodemo;??
  • ??
  • public?interface?PersonDao??
  • {??
  • ????public?Person?fetchPerson(?Integer?personID?);??
  • ????public?void?update(?Person?person?);??
  • }???
  •   類PersonService.java
    [java]?view plaincopy
  • package?mockitodemo;??
  • ??
  • public?class?PersonService??
  • {??
  • ????private?final?PersonDao?personDao;??
  • ????public?PersonService(?PersonDao?personDao?)??
  • ????{??
  • ????????this.personDao?=?personDao;??
  • ????}??
  • ????public?boolean?update(?Integer?personId,?String?name?)??
  • ????{??
  • ????????Person?person?=?personDao.fetchPerson(?personId?);??
  • ????????if(?person?!=?null?)??
  • ????????{??
  • ????????????Person?updatedPerson?=?new?Person(?person.getPersonID(),?name?);??
  • ????????????personDao.update(?updatedPerson?);??
  • ????????????return?true;??
  • ????????}??
  • ????????else??
  • ????????{??
  • ????????????return?false;??
  • ????????}??
  • ????}??
  • }???
  • 步驟 3: ?添加單元測試類.??

      接下來為類PersonService.java創建單元測試用例。我們使用JUnit 4.x和Mockito 1.9.5。可以設計測試用例類PersionServiceTest.java為如下,代碼中有詳細注釋說明:

    [java]?view plaincopy
  • package?mockitodemo;??
  • ??
  • import?org.junit.After;??
  • import?org.junit.AfterClass;??
  • import?org.junit.Before;??
  • import?org.junit.BeforeClass;??
  • import?org.junit.Test;??
  • import?static?org.junit.Assert.*;??
  • import?org.mockito.Mock;??
  • import?org.mockito.MockitoAnnotations;??
  • import?org.mockito.ArgumentCaptor;??
  • import?static?org.mockito.Mockito.*;??
  • ??
  • /**?
  • ?*?PersonService的單元測試用例?
  • ?*?
  • ?*?@author?jackzhou?
  • ?*/??
  • public?class?PersonServiceTest?{??
  • ??
  • ????@Mock??
  • ????private?PersonDao?personDAO;??//?模擬對象??
  • ????private?PersonService?personService;??//?被測類??
  • ??
  • ????public?PersonServiceTest()?{??
  • ????}??
  • ??
  • ????@BeforeClass??
  • ????public?static?void?setUpClass()?{??
  • ????}??
  • ??
  • ????@AfterClass??
  • ????public?static?void?tearDownClass()?{??
  • ????}??
  • ??
  • ????//?在@Test標注的測試方法之前運行??
  • ????@Before??
  • ????public?void?setUp()?throws?Exception?{??
  • ????????//?初始化測試用例類中由Mockito的注解標注的所有模擬對象??
  • ????????MockitoAnnotations.initMocks(this);??
  • ????????//?用模擬對象創建被測類對象??
  • ????????personService?=?new?PersonService(personDAO);??
  • ????}??
  • ??
  • ????@After??
  • ????public?void?tearDown()?{??
  • ????}??
  • ??
  • ????@Test??
  • ????public?void?shouldUpdatePersonName()?{??
  • ????????Person?person?=?new?Person(1,?"Phillip");??
  • ????????//?設置模擬對象的返回預期值??
  • ????????when(personDAO.fetchPerson(1)).thenReturn(person);??
  • ????????//?執行測試??
  • ????????boolean?updated?=?personService.update(1,?"David");??
  • ????????//?驗證更新是否成功??
  • ????????assertTrue(updated);??
  • ????????//?驗證模擬對象的fetchPerson(1)方法是否被調用了一次??
  • ????????verify(personDAO).fetchPerson(1);??
  • ????????//?得到一個抓取器??
  • ????????ArgumentCaptor<Person>?personCaptor?=?ArgumentCaptor.forClass(Person.class);??
  • ????????//?驗證模擬對象的update()是否被調用一次,并抓取調用時傳入的參數值??
  • ????????verify(personDAO).update(personCaptor.capture());??
  • ????????//?獲取抓取到的參數值??
  • ????????Person?updatePerson?=?personCaptor.getValue();??
  • ????????//?驗證調用時的參數值??
  • ????????assertEquals("David",?updatePerson.getPersonName());??
  • ????????//?asserts?that?during?the?test,?there?are?no?other?calls?to?the?mock?object.??
  • ????????//?檢查模擬對象上是否還有未驗證的交互??
  • ????????verifyNoMoreInteractions(personDAO);??
  • ????}??
  • ??
  • ????@Test??
  • ????public?void?shouldNotUpdateIfPersonNotFound()?{??
  • ????????//?設置模擬對象的返回預期值??
  • ????????when(personDAO.fetchPerson(1)).thenReturn(null);??
  • ????????//?執行測試??
  • ????????boolean?updated?=?personService.update(1,?"David");??
  • ????????//?驗證更新是否失敗??
  • ????????assertFalse(updated);??
  • ????????//?驗證模擬對象的fetchPerson(1)方法是否被調用了一次??
  • ????????verify(personDAO).fetchPerson(1);??
  • ????????//?驗證模擬對象是否沒有發生任何交互??
  • ????????verifyZeroInteractions(personDAO);??
  • ????????//?檢查模擬對象上是否還有未驗證的交互??
  • ????????verifyNoMoreInteractions(personDAO);??
  • ????}??????
  • ??
  • ????/**?
  • ?????*?Test?of?update?method,?of?class?PersonService.?
  • ?????*/??
  • ????@Test??
  • ????public?void?testUpdate()?{??
  • ????????System.out.println("update");??
  • ????????Integer?personId?=?null;??
  • ????????String?name?=?"Phillip";??
  • ????????PersonService?instance?=?new?PersonService(new?PersonDao()?{??
  • ??
  • ????????????@Override??
  • ????????????public?Person?fetchPerson(Integer?personID)?{??
  • ????????????????System.out.println("Not?supported?yet.");??
  • ????????????????return?null;??
  • ????????????}??
  • ??
  • ????????????@Override??
  • ????????????public?void?update(Person?person)?{??
  • ????????????????System.out.println("Not?supported?yet.");??
  • ????????????}??
  • ????????});??
  • ????????boolean?expResult?=?false;??
  • ????????boolean?result?=?instance.update(personId,?name);??
  • ????????assertEquals(expResult,?result);??
  • ????????//?TODO?review?the?generated?test?code?and?remove?the?default?call?to?fail.??
  • ????????fail("The?test?case?is?a?prototype.");??
  • ????}??
  • }??
  •   這里setUpClass()、tearDownClass()、setUp()、tearDown()稱為測試夾具(Fixture),就是測試運行程序(test runner)在運行測試方法之前進行初始化、或之后進行回收資源的工作。JUnit 4之前是通過setUp、tearDown方法完成。在JUnit 4中,仍然可以在每個測試方法運行之前初始化字段和配置環境,當然也是通過注解完成。在JUnit 4中,通過@Before標注setUp方法;@After標注tearDown方法。在一個測試類中,甚至可以使用多個@Before來注解多個方法,這些方法都是在每個測試之前運行。說明一點,一個測試用例類可以包含多個打上@Test注解的測試方法,在運行時,每個測試方法都對應一個測試用例類的實例。@Before是在每個測試方法運行前均初始化一次,同理@Ater是在每個測試方法運行完畢后均執行一次。也就是說,經這兩個注解的初始化和注銷,可以保證各個測試之間的獨立性而互不干擾,它的缺點是效率低。另外,不需要在超類中顯式調用初始化和清除方法,只要它們不被覆蓋,測試運行程序將根據需要自動調用這些方法。超類中的@Before方法在子類的@Before方法之前調用(與構造函數調用順序一致),@After方法是子類在超類之前運行。
      這里shouldUpdatePersonName()、shouldNotUpdateIfPersonNotFound()和testUpdate()都是測試PersonService的update()方法,它依賴于PersonDao接口。前兩者使用了模擬測試。testUpdate()則沒有使用模擬測試。下面是測試結果:

    圖4 測試結果點擊打開鏈接

      可以看出,使用模擬測試的兩個測試成功了,沒有使用模擬測試的testUpdate()失敗。對于模擬測試,在測試用例類中要先聲明依賴的各個模擬對象,在setUp()中用MockitoAnnotations.initMocks()初始化所有模擬對象。在進行模擬測試時,要先設置模擬對象上方法的返回預期值,執行測試時會調用模擬對象上的方法,因此要驗證這些方法是否被調用,并且傳入的參數值是否符合預期。對于testUpdate()測試,我們需要自己創建測試PersonService.update()所需的所有PersonDao數據,因為我們只知道公開的PersonDao接口,其具體實現類(比如從數據庫中拿真實的數據,或寫入到數據庫中)可能由另一個團隊在負責,以適配不同的數據庫系統。這樣的依賴關系無疑使單元測試比較麻煩,而要拿真正PersonDao實現來進行測試,那也應該是后期集成測試的任務,把不同的組件集成到一起在真實環境中測試。有了模擬測試框架,就可以最大限度地降低單元測試時的依賴耦合性。

    關注點?

    ?+ Mock框架是什么.

    ?+ 為什么要在測試中使用Mockito.?

    參考

    http://java.dzone.com/articles/the-concept-mocking??

    http://en.wikipedia.org/wiki/Mockito?

    http://code.google.com/p/mockito


    本文翻譯自:http://www.codeproject.com/Articles/516360/Mockito-a-great-mock-framework-for-Java-developmen?,并做了一些修改。


    from:?http://blog.csdn.net/zhoudaxia/article/details/33056093

    總結

    以上是生活随笔為你收集整理的Mockito:一个强大的用于Java开发的模拟测试框架的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    主站蜘蛛池模板: 72pao成人国产永久免费视频 | 中文字幕3页 | 欧美成人免费大片 | 偷拍第一页 | 日韩毛片一区二区三区 | 国产性猛交xxxⅹ交酡全过程 | 亚洲13p| 91视频国产精品 | 中文在线资源 | 国产综合视频一区 | 538精品在线视频 | 精品成在人线av无码免费看 | 精品国产免费观看 | 亚洲乱码国产乱码精品精软件 | 日夜夜操 | 网站在线免费观看 | 一级黄色在线观看 | 亚洲午夜精品久久久久久人妖 | 欧美人人爽 | 拔擦8x成人一区二区三区 | 日韩精品亚洲一区 | 精品国产乱码久久久久久预案 | 久久99精品国产.久久久久久 | 亚洲国产剧情在线观看 | 美女激情网 | 欧美精品一二区 | 日日精 | 少妇视频一区二区三区 | 性感美女福利视频 | 91自啪| 日本人与黑人做爰视频 | 懂色一区二区三区免费观看 | 久久精品国产99久久不卡 | 成人黄色小说在线观看 | 久久网站免费观看 | 色婷婷亚洲综合 | 亚洲福利 | 91精品国自产在线 | 欧美日韩成人在线观看 | xxxxxxxx黄色片 | 在线aaa| 91性视频| 成人激情综合 | 日本少妇做爰全过程毛片 | 国产偷人爽久久久久久老妇app | 999福利视频 | 中文字幕一区不卡 | 成年人在线免费观看 | 性开放淫合集 | 僵尸叔叔在线观看国语高清免费观看 | 艳妇乳肉亭妇荡乳av | 欧美久久久久久久久久久 | 久久精品视频观看 | 不用播放器av | 8050午夜一级毛片久久亚洲欧 | 日产精品久久久久 | 一个色在线 | 亚洲精品视频播放 | 在线免费观看黄网 | 成人在线高清视频 | 亚洲福利一区二区 | 国产精品久久久免费视频 | 亚洲激情一区 | 插插插91| 加勒比av在线播放 | 熟女少妇在线视频播放 | 婷婷色在线 | 日本国产高清 | 日本免费毛片 | 久草午夜 | 国产三级在线看 | 激情av在线播放 | 欧美黄色免费网站 | av影院在线播放 | 国内偷拍久久 | 青青视频在线播放 | 色乱码一区二区三区在线男奴 | 老女人综合网 | 91干网| 男女做受视频 | 亚洲自拍偷拍色图 | 久久调教视频 | 日韩中文字幕第一页 | 少妇按摩一区二区三区 | 天天干天天综合 | 96在线视频 | 秋霞影院午夜老牛影院 | 一区二区三区播放 | 在线午夜电影 | 不卡av在线播放 | www.成人av.com| 成人乱人乱一区二区三区一级视频 | 国产精品自在线 | 国产av电影一区二区三区 | 秋霞网一区二区三区 | 久久无毛 | 日韩精品在线视频免费观看 | 永久av网站 | 91视频观看 |