1. 程式人生 > >比較完整的junit單元測試之-----mock模擬測試

比較完整的junit單元測試之-----mock模擬測試

為什麼需要模擬? 

  在我們一開始學程式設計時,我們所寫的物件通常都是獨立的。hello world之類的類並不依賴其他的類(System.out除外),也不會操作別的類。但實際上軟體中是充滿依賴關係的。我們會基於service類寫操作類,而service類又是基於資料訪問類(DAOs)的,依次下去。

圖1 類的依賴關係

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

  下面的程式碼就是這樣的例子:

  1. import java.util.ArrayList;  
  2. publicclass Counter {  
  3.      public Counter() {  
  4.      }  
  5.      publicint count(ArrayList items) {  
  6.           int results = 0;  
  7.           for(Object curItem : items) {  
  8.                results ++;  
  9.           }  
  10.           return results;  
  11.      }  
  12. }   
  如你所見,上面的例子十分簡單,但它闡明瞭要點。當你想要測試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模式(期望--執行--驗證模式),因此使耦合度降低到最低。這樣的突出特性簡化了測試程式碼,使它更容易閱讀和修改了。

你可以驗證互動:

  1. // 模擬的建立,對介面進行模擬
  2. List mockedList = mock(List.class);  
  3. // 使用模擬物件
  4. mockedList.add("one");  
  5. mockedList.clear();  
  6. // 選擇性地和顯式地驗證
  7. verify(mockedList).add("one");  
  8. verify(mockedList).clear();    

或者存根方法呼叫:

  1. // 你不僅可以模擬介面,任何具體類都行
  2. LinkedList mockedList = mock(LinkedList.class);  
  3. // 執行前準備測試資料
  4. when(mockedList.get(0)).thenReturn("first");  
  5. // 接著列印"first"
  6. System.out.println(mockedList.get(0));  
  7. // 因為get(999)未對準備資料,所以下面將列印"null".
  8. System.out.println(mockedList.get(999));   

一個使用Mockito框架的簡單Java程式碼示例



圖2 不使用Mock框架


圖3 使用Mockito框架

步驟 1:  在IDE中建立一個普通的Java專案 

  在Eclipse、NetBeans或IntelliJ IDEA中建立一個普通的Java專案。

步驟 2:  新增java原始碼  

  類Person.java:

  1. package mockitodemo;  
  2. publicclass Person  
  3. {  
  4.     privatefinal Integer personID;  
  5.     privatefinal String personName;  
  6.     public Person( Integer personID, String personName )  
  7.     {  
  8.         this.personID = personID;  
  9.         this.personName = personName;  
  10.     }  
  11.     public Integer getPersonID()  
  12.     {  
  13.         return personID;  
  14.     }  
  15.     public String getPersonName()  
  16.     {  
  17.         return personName;  
  18.     }  
  19. }   
  介面PersonDAO.java
  1. package mockitodemo;  
  2. publicinterface PersonDao  
  3. {  
  4.     public Person fetchPerson( Integer personID );  
  5.     publicvoid update( Person person );  
  6. }   
  類PersonService.java
  1. package mockitodemo;  
  2. publicclass PersonService  
  3. {  
  4.     privatefinal PersonDao personDao;  
  5.     public PersonService( PersonDao personDao )  
  6.     {  
  7.         this.personDao = personDao;  
  8.     }  
  9.     publicboolean update( Integer personId, String name )  
  10.     {  
  11.         Person person = personDao.fetchPerson( personId );  
  12.         if( person != null )  
  13.         {  
  14.             Person updatedPerson = new Person( person.getPersonID(), name );  
  15.             personDao.update( updatedPerson );  
  16.             returntrue;  
  17.         }  
  18.         else
  19.         {  
  20.             returnfalse;  
  21.         }  
  22.     }  
  23. }   

步驟 3:  新增單元測試類.  

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

  1. package mockitodemo;  
  2. import org.junit.After;  
  3. import org.junit.AfterClass;  
  4. import org.junit.Before;  
  5. import org.junit.BeforeClass;  
  6. import org.junit.Test;  
  7. importstatic org.junit.Assert.*;  
  8. import org.mockito.Mock;  
  9. import org.mockito.MockitoAnnotations;  
  10. import org.mockito.ArgumentCaptor;  
  11. 相關推薦

    比較完整junit單元測試-----mock模擬測試

    為什麼需要模擬?    在我們一開始學程式設計時,我們所寫的物件通常都是獨立的。hello world之類的類並不依賴其他的類(System.out除外),也不會操作別的類。但實際上軟體中是充滿依賴關係的。我們會基於service類寫操作類,而service類又是基於資料訪問類(DAOs)的,依

    python筆記24-unittest單元測試mock.patch

    rom Coding int self. 錯誤 測試用例 方法 org auto 前言 上一篇python筆記23-unittest單元測試之mock對mock已經有初步的認識, 本篇繼續介紹mock裏面另一種實現方式,patch裝飾器的使用,patch() 作為函數裝飾器

    單元測試Mock(Moq)

    inter 商品 void 簡單 calc 不用 準備 targe ted Mock翻譯為“嘲弄”,其實就是偽造一個對象用於測試。在單元測試中,被測試方法依賴於其他對象時,為了測試簡單一般“偽造”一個這個對象;這樣做的目的: 不用考慮依賴對象的復雜性(方便準備測試數據)

    [OpenStack UT] 分析OpenStack中單元測試mock & mox

    在社群貢獻OpenStackcode時,會經常短短的幾行程式碼也要新增不少的UT,耗時耗力,mock & mox 是很好的實現隔離的單元測試模組, 理解它們能夠更快的做UT的編碼。 mock & mox:  都是python中用於實現單元測試的module

    python筆記23-unittest單元測試mock

    顯示 現實 name pan blog 我只 服務 接口 模擬 unittest.mock是一個用於在Python中進行單元測試的庫,Mock翻譯過來就是模擬的意思,顧名思義這個庫的主要功能是模擬一些東西。它的主要功能是使用mock對象替代掉指定的Python對象,以達

    golang單元測試mock

    搞單元測試,如果碰到這些情況: 1,一個函式,內部包含了很多並且很深的呼叫,但是如果單單測這個函式,其實實現的功能很簡單。 2,一個函式,包含了其他還未實現的呼叫。 3,函式內部對資料的要求極為苛刻。 那麼這時候就可以考慮使用mock來處理。 mock

    走進Java介面測試Mock(概念篇)

    文章目錄 引言 Mock 的定義 Mock 的分類 Mock 一個物件 Mock Server 小結 引言 實際工作中,測試人員可能會遇到如下情況: 場景一:依賴介面不通,甲

    Mock 模擬測試簡介及 Mockito 使用入門

    Mock 是什麼mock 測試就是在測試過程中,對於某些不容易構造或者不容易獲取的物件,用一個虛擬的物件來建立以便測試的測試方法。這個虛擬的物件就是mock物件。mock物件就是真實物件在除錯期間的代替品。 簡單的看一張圖   我們在測試類 A 時,類 A 需要呼叫類 B 和類 C,而類 B

    Junit學習筆記三:測試驅動開發

    1.正常的開發流程 編碼--->測試--->重複--->提交 基於測試驅動的開發 測試--->編碼--->重複--->提交 先寫了測試之後,由於測試的覆蓋率要求為100%,所以就會讓程式碼中可能存在的分支都進行測試,這樣先寫測試單元,可以

    python介面測試mock(九)

    初步的介紹,今天這裡繼續接著之前的介紹進行,我們先看之前的mock-server部分,之前編寫 了一個登入的mock,具體json檔案見如下的內容: [ { "request": { "method":"post", "

    Visual Studio 單元測試三---壓力測試

          我們都知道大名鼎鼎的LoadRuner,但是很少有人知道Visual Studio自帶的Test也可以做些簡單的壓力測試,下面我們就介紹一下如何利用Visual Studio進行壓力測試。 本文會自動略去上篇中提到過的相關概念、方法。本文的例子可以使用下面的連

    Visual Studio 單元測試五---資料庫測試

    資料庫的單元測試主要是測試資料庫中的資料是否符合特定的條件,Visual Studio 2010支援下面幾種資料的單元測試型別(Visual Studio 2008 不支援資料庫測試): 型別 說明 Data Checksum 對資料進行Checksum檢驗

    服務端測試接口測試初探

    公開課 sock 先來 設計 自動化腳本 提供服務 傳遞數據 格式 什麽是   提起服務端測試,第一反應想到的可能就是http協議、socket連接、post/get發送請求等等。回想起小編當時初次接觸服務端測試,真可謂一臉懵逼,不知道要幹什麽也不知道從哪兒開始做。服務端測

    服務端測試接口測試用例設計

    key 文檔 取數據 正常 驗證 性能測試 通過 工具使用 兩個 小夥伴們大家好,上一次和大家分享了《服務端測試之接口測試初探》,講了一些接口測試的基本概念和理論知識。在上次的分享中,簡單提到了接口測試用例設計包含的幾個方面。本期我將在上次分享的基礎上,和各位小夥伴一起具體

    軟件測試“白盒測試

    performed CA 報告 測試框架 threading program 連接 ott nat 【引言】工作關系,作為曾經的獨立測試部門,現在與開發團隊一起組成Scrum Team融合階段。 因為以前的項目系統問題較多,上邊大老板為了提高開發團隊的代碼提交質量,要求開發

    軟件測試兵器篇——測試工具【轉】

    電話 跨項目 spa studio 桌面應用 mar 設備 也有 gin 功能測試篇   功能測試,是軟件測試裏的入門級心法,自然也有與之相對應的兵器來發揮心法的最大功力。 1) 屠龍刀之QTP 屠龍刀是金庸小說裏排名第一的寶刀,重劍無鋒,無堅不摧。素有“武林至尊,寶刀屠

    App專項測試弱網測試

    之前跟同事聊天的時候發現一個問題,很多的公司在沒有自主研發的弱網測試工具的時候很少有人去做這個弱網測試,而且弱網測試作為健壯測試的重要部分,對於移動端測試來說必不可少。這是因為目前移動端產品的使用使用者所處的網路並非完全的流暢WIFI環境,仍有相當多的使用者主要使用4G、3G、2G等網路,另外因移動端產品使用

    WEB介面測試Jmeter介面測試自動化之一

     1、開啟jmeter           開源版本和可執行版本均可在Apache官方網站上下載到,解壓後開啟bin目錄下的jmeter.bat檔案,即打開了使用者介面:                     2、新增相關元件          2.1、新建執行

    WEB介面測試Jmeter介面測試自動化四 持續構建

    Jmeter是壓力測試、介面測試工具,Ant是基於Java的構建工具,具有跨平臺的作用,jenkins是持續整合工具。將這三者結合起來可以搭建一套webservice介面測試的持續構建環境。   1、安裝JDK,配置java環境變數(略過) 2、安裝Jmeter,這裡

    前端測試使用者體驗測試

    前言           最近專案中涉及了大量的前端頁面類測試,如小程式、H5等多個B、C端的測試,故而想把一些心得記錄下來,僅供大家參考。這裡僅僅對前端測試中涉及的需求層面的問題做簡單剖析,希望藉此來拋磚引玉。 前端測試的困境         回顧從剛剛入門測試到現在