1. 程式人生 > >Mockito一個用於Java開發的偉大的模擬框架

Mockito一個用於Java開發的偉大的模擬框架

介紹

這個藝術將展示mock框架的一些基本概念,為什麼我們應該使用它,並演繹一個在Java中應用Mockito的簡單方法。

Mock的概念

在軟體開發世界之外,術語“mock”意味著模仿或模擬。因此,“mock”可以被認為是一種獨立的,冒名頂生的,或者最常被稱之為軟體開發,一種fake

假貨經常被用作待測類的依賴關係。

條款和定義
依賴關係- 依賴關係是指應用程式中的一個類別依賴於另一個類來執行其預期功能。依賴關係通常儲存在依賴類中的例項變數中。
被試課程- 在進行單元測試時,術語“單元”通常是指一個單獨的類,特別是測試寫入的類。因此,被測試類是正在測試的應用程式類。

為什麼模擬?

當我們學習程式設計時,我們的物件通常是自包含的。

任何你好的世界都沒有依賴於外部類(System.out),也不會在學習語言的過程中寫入許多其他類。然而,在現實世界中,軟體具有依賴性。我們有依賴於資料訪問物件(DAO)的服務和服務的操作類,列表繼續。

單元測試的想法是我們要測試我們的程式碼而不測試依賴。此測試允許您驗證正在測試的程式碼是否工作,而不管其是否依賴。理論是,如果我寫的程式碼按照設計工作,我的依賴關係按照設計工作,那麼他們應該按照設計一起工作。下面的程式碼將是一個例子:

Hide Copy Code
import java.util.ArrayList;
public class Counter {
     public Counter() {
     }
     public int count(ArrayList items) {
          int results = 0;
          for(Object curItem : items) {
               results ++;
          }
          return results;
     }
} 

我知道上面的例子就像你所得到的一樣簡單,但是它說明了一點。如果您想測試方法計數,您將在測試中寫入,以解決計數方法的工作原理。您不是試圖測試ArrayList的工作原理,因為您假設它已經過測試並按照設計工作您唯一的目標是測試您對ArrayList的使用。

模擬物件背後的概念是我們想要建立一個取代真實物件的物件。這個模擬物件將期望使用某些引數呼叫某種方法,而在這種情況下,它將返回一個預期的結果。

什麼是關鍵的Mock概念?

當談到mock時,你只需要3件事情就需要擔心;扼殺,設定期望和驗證。某些單元測試場景不涉及任何這些情況,其他單獨測試場景只涉及樁杆,而其他則涉及設定預期和驗證。

存根

Stubbing是告訴你的假的過程,當它與它進行互動時如何表現。

您通常可以存放公共屬性(帶有getter和/或setter的公共屬性)和公共函式。

說到stubbing功能,你通常有很多選擇。您可能希望返回特定值,丟擲錯誤或排程事件。此外,您可能希望指示函式的行為方式取決於呼叫方式(即通過匹配傳遞給函式的引數的型別或值)。

如果這聽起來像是很多的工作,它可以是,但它一般不是。許多mock框架的一個很大的特點是你不需要stub void函式。您也不必在執行測試過程中儲存任何未被呼叫的函式或未查詢的屬性。

設定期望

假冒的主要特徵之一就是能夠告訴假冒測試執行時的期望。例如,您可能希望呼叫一個特定的函式3次。你可能期望它永遠不會被呼叫。您可能希望它至少被呼叫兩次,但不要超過5次。您可能希望使用特定型別的引數或特定值或上述任何組合來呼叫它。可能性是無止境的。

設定期望是告訴你假的你會發生什麼的過程。記住,由於它是假的,實際上沒有發生。但是,你被測試的班級並不聰明。從它的角度來看,它呼叫了這個函式,並期望它做了它應該做的任何事情。

對於什麼是值得的,大多數嘲笑框架可以讓您建立介面或公共類的模擬。您不限於僅僅模擬介面。

驗證

設定期望和驗證是並存的。在呼叫被測試類的函式之前,設定期望值。驗證完成。所以,首先你設定了期望,然後驗證你的期望是否得到滿足。

從單元測試的角度來看,如果您的期望未得到滿足,則單元測試失敗。例如,如果您設定了ILoginService.login函式應該使用特定的使用者名稱和密碼一次呼叫的期望,但是在執行測試期間它並沒有被呼叫,則該偽造不會被驗證,並且測試失敗。

Mock的好處是什麼?

您可以提前建立測試;TDD

這一個是更強大的好處之一。如果您建立一個模擬器,您可以在服務建立之前編寫服務測試,使您能夠在開發過程中將測試新增到自動化環境中。換句話說,Service Mocking可以讓您使用測試驅動開發。

團隊可以並行工作

這與上述類似為不存在的程式碼建立測試。但是以前的一點是針對開發人員編寫測試,這是針對測試團隊的。當您沒有任何測試時,團隊如何開始建立測試?模擬它,並對模擬器進行測試!這意味著當服務準備好進行測試時,QA團隊實際上可以準備一整套測試;我們沒有停機的時候,一個隊伍等待另一個完成。這使得嘲弄的財務論據特別強。

您可以建立概念或演示的證明。

由於Mocks可以(成本最高)能夠實現成本效益,因此可以使用Mocks來建立概念證明,線框架,或作為您正在考慮構建的應用程式的演示。這是非常強大的,為決定是否繼續開發專案做出決定,但最重要的是為實際設計決策提供了良好的基礎。

您可以編寫測試資源不可訪問

這是不屬於實際利益類別的好處之一,而是作為救生員。曾經想要測試或使用服務,只是被告知該服務是在防火牆後面,那個防火牆無法為您開啟,或者您被授權使用該防火牆?當你這樣做時,一個MockService放置在可訪問的地方,包括在你本地的電腦上,是一個救命的人。

模擬器可以交付給客戶

有些情況下,您無法允許訪問外部來源的測試系統(如合作伙伴或客戶)的原因。這些原因可以是訪問安全性,資訊敏感性,或只是測試環境可能無法24/7訪問的事實。在這些情況下您如何為您的合作伙伴或客戶提供測試系統以開始開發或測試?一個簡單的解決方案是從您的網路或客戶自己的網路提供一個模擬。soapUI模擬是非常容易部署的,它可以在soapUI中執行,也可以作為.WAR檔案匯出,並放置在您選擇的Java伺服器中。

您可以隔離系統

有時您想測試系統的一部分,而不會影響其他系統部件。這是因為其他系統會對測試資料增加噪音,使得從收集的資料中得出更好的結論更加困難。使用mocks,您可以刪除所有的系統,嘲笑所有系統,除了您在測試中需要確定的一個系統。當進行嘲諷隔離時,這些嘲弄可以做得非常簡單但可靠,快速,可預測。這給您一個測試環境,您已經刪除了所有隨機行為,具有可重複的模式,並可以很好地監控特定系統。

Mockito框架

Mockito是根據MIT許可證釋出的Java開源測試框架。
Mockito通過允許開發人員預先確定被測系統(SUT)的行為來區別於其他嘲笑框架。[4]對模擬物件的批評之一是測試程式碼與被測系統的緊密耦合。[5]由於Mockito試圖通過消除預期的規範來消除預期執行驗證模式[6],所以耦合被減小或最小化。這個區別功能的結果是更簡單的測試程式碼,應該更容易閱讀和修改。

您可以驗證互動:

Hide Copy Code
// mock creation
List mockedList = mock(List.class);
// using mock object
mockedList.add("one");
mockedList.clear();
// selective and explicit vertification
verify(mockedList).add("one");
verify(mockedList).clear();   

或存根方法呼叫

Hide Copy Code
// you can mock concrete class, not only interfaces
LinkedList mockedList = mock(LinkedList.class);
// stubbing - before execution
when(mockedList.get(0)).thenReturn("first");
// following prints "first"
System.out.println(mockedList.get(0));
// following prints "null" because get(999) was not stubbed.
System.out.println(mockedList.get(999)); 

使用Mockito的簡單示例Java程式碼


沒有Mock框架


用Mockito框架

步驟1:在Eclipse中建立一個Maven專案

定義pom.xml如下:

Hide Shrink Copy Code
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 

         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>vn.com.phatbeo.ut.mockito.demo</groupId>
  <artifactId>demoMockito</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>demoMockito</name>
  <url>http://maven.apache.org</url>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <build>
    <sourceDirectory>src</sourceDirectory>
    <testSourceDirectory>test</testSourceDirectory>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.1</version>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
        </configuration>
      </plugin>
      </plugins>
  </build>
  
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-all</artifactId>
      <version>1.8.5</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  
</project> 

步驟2:新增java原始碼

Person.java

Hide Copy Code
  package vn.com.enclave.phatbeo.ut.mockito.demo;
/** 
 * @author Phat (Phillip) H. VU <[email protected]>
 *  
 */ 
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

Hide Copy Code
 package vn.com.enclave.phatbeo.ut.mockito.demo;
/**
 * @author Phat (Phillip) H. VU <[email protected]>
 * 
 */
public interface PersonDao
{
    public Person fetchPerson( Integer personID );
    public void update( Person person );
} 

PersonService.java

Hide Shrink Copy Code
 package vn.com.enclave.phatbeo.ut.mockito.demo;
/**
 * @author Phat (Phillip) H. VU <[email protected]com>
 * 
 */
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類的單元測試用例

假設類PersionServiceTest.java如下所示:

Hide Shrink Copy Code
 package vn.com.enclave.phatbeo.ut.mockito.demo.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
 * @author Phat (Phillip) H. VU <[email protected]>
 * 
 */
public class PersonServiceTest
{
    @Mock
    private PersonDao personDAO;
    private PersonService personService;
    @Before
    public void setUp()
        throws Exception
    {
        MockitoAnnotations.initMocks( this );
        personService = new PersonService( personDAO );
    }
    @Test
    public void shouldUpdatePersonName()
    {
        Person person = new Person( 1, "Phillip" );
        when( personDAO.fetchPerson( 1 ) ).thenReturn( person );
        boolean updated = personService.update( 1, "David" );
        assertTrue( updated );
        verify( personDAO ).fetchPerson( 1 );
        ArgumentCaptor<Person> personCaptor = ArgumentCaptor.forClass( Person.class );
        verify( personDAO ).update( personCaptor.capture() );
        Person updatedPerson = personCaptor.getValue();
        assertEquals( "David", updatedPerson.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 );
        verify( personDAO ).fetchPerson( 1 );
        verifyZeroInteractions( personDAO );
        verifyNoMoreInteractions( personDAO );
    }
} 

興趣點

+什麼是Mock框架在概述。

+為什麼我們在Java開發中使用Mockito進行測試。

參考文獻

歷史

2012年12月26日首發

相關推薦

Mockito一個用於Java開發偉大模擬框架

介紹這個藝術將展示mock框架的一些基本概念,為什麼我們應該使用它,並演繹一個在Java中應用Mockito的簡單方法。Mock的概念在軟體開發世界之外,術語“mock”意味著模仿或模擬。因此,“mock”可以被認為是一種獨立的,冒名頂生的,或者最常被稱之為軟體開發,一種fake。假貨經常被用作待測類的依賴關

Mockito一個強大的用於Java開發模擬測試框架

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

IntelliJ IDEA詳細配置和使用教程(適用於Java開發人員)

前言 正所謂工欲善其事必先利其器,對開發人員而言若想提高編碼效率,一款高效的開發工具是必不可少的,相信看到該部落格的朋友們都已經對IntelliJ IDEA有所瞭解了,所以此處就不對IntelliJ IDEA進行介紹,而是直接闡述在實際開發中應用場景。博主使用

一個JAVA開發的程式設計師都應該知道的JAVA發展史

作為一名Java語言的學習者,對Java的起源和發展有個大概的瞭解應是必要的。 小編給大家講個有趣的小故事,JAVA名字的來源,有兩種版本,其中一種可信度雖然不高,但仍有人聲稱是開發人員名字的組合:JamesGosling(詹姆斯·高斯林)ArthurVanHoff(阿瑟·凡·霍夫)AndyBech

JAVA開發使用SSM框架入門案例

本案例主要做一個簡單的SSM搭建,完成根據ID查詢部門表中資訊並在瀏覽器中顯示。使用Idea2015+jdk1.8+oracle11g,在這個專案中,會使用使用Mavn-MyBatis逆向工程外掛,反向生成程式碼(即通過資料庫表生成DAO介面,Mapper.xml SQL對映

一個JAVA開發的會話金鑰程式

/* 執行本程式你需要下載JCE,Bouncy Castle的JCE with Provider and Lightweight API 網址是 http://www.bouncycastle.org配置如下: 在Windows中,你需要把下載的bcprov-JDK14-11

JAVA開發Web Service幾種框架介紹

需求 驚人的 總線 cast pri web服務 希望 uil blank 在講Web Service開發服務時,需要介紹一個目前開發Web Service的幾個框架,分別為Axis,axis2,Xfire,CXF以及JWS(也就是前面所述的JAX-WS,這是Java

Java EE開發四大常用框架

javaee spring hibernate struts 我們對Java EE的框架有過很多介紹, 本文將對Java EE中常用的四個框架做一下系統的歸納,希望大家喜歡。 StrutsStruts是一個基於Sun Java EE平臺的MVC框架,主要是采用Servlet和JSP技術來實現的

為什麽bug這麽多,論一個規範的開發框架重要性

十個 代碼層次 為什麽 二次 方法 .com 管理 height img 在公司做項目二次開發快一年了,說實話,每次我和同事調侃,寫一個星期代碼,就要改一個月bug,心累。為什麽我會產出這麽多bug,我技術很low嗎?我是程序員渣渣?捫心自問,我不服啊 每次做單獨項目接口

我的第一個python web開發框架(2)——一個簡單的小外包

span 技術 進行 target 最好 自己 blog height 描述   第一部分說明   第一部分大概有20來章,主要講的是一些開發常識、開發前中後期準備內容、開發環境與服務器部署環境安裝設置、python基礎框架結構與功能等內容,代碼會比較簡單。   

我的第一個python web開發框架(4)——數據庫結構設計與創建

數據結構 描述 分析器 設置 一個 由於 logs 記錄 開發框架   小白做好前端html設計後,馬上開始進入數據庫結構設計步驟。      在開始之前,小白回憶了一下老大在公司裏培訓時講過的數據庫設計解說:   對於初學者來說,很多拿到原型時不知道怎麽設計數據表結

我的第一個python web開發框架(5)——開發前準備工作(了解編碼前需要知道的一些常識)

turn 框架 strong pep8 加密與解密 python開發 lan 二次 沒有   中午吃飯時間到了,小白趕緊向老菜坐的位置走過去。   小白:老大,中午請你吃飯。   老菜:哈哈...又遇到問題了吧,這次得狠狠宰你一頓才行。   小白:行行行,只要您賞臉,

我的第一個python web開發框架(15)——公司介紹編輯功能

getcwd 轉義 導航菜單 unicode 存儲路徑 -c 序號 管理 bsp   完成登錄以後,就會進入後臺管理系統的主界面,因為這個是小項目,所以導航菜單全部固化在HTML中,不能修改。一般後臺還會有一個歡迎頁或關鍵數據展示的主頁面,小項目也沒有多大的必要,所以登錄後

我的第一個python web開發框架(16)——產品分類管理

計算 添加按鈕 _for records 操作 qq群 api 回復 derby   產品分類管理的html頁面之前忘記做了,這次附件裏補上。   好了先上圖      從頁面效果圖來看,我們需要開發列表獲取接口、添加接口、單條記錄獲取接口、編輯接口和刪除接口   

我的第一個python web開發框架(18)——前臺頁面與接口整合

ont 成功 讀取數據 pad images int 服務器 tps 替換   由於我們前後臺系統沒有分開,所以前臺頁面調用接口時,可以直接使用後臺管理系統已經完成的接口,不過後臺管理系統接口的訪問加上了登錄驗證,所以需要將前臺要用到的接口進行處理,讓它們設置到白名單當中

我的第一個python web開發框架(21)——小結

線上 天下 謝謝 應用 log 增加 頁面 管理員 封裝   這個小網站終於成功上線,小白除了收獲一筆不多的費用外,還得到女神小美的贊賞,心中滿滿的成就感。這一天下班後,他請老菜一起下館子,兌現請吃飯的承諾,順便讓老菜點評一下。   小白:老大,在你的指導下終於完成了我人

搭建一個java開發環境的步驟

配置 還需要 配置jdk cat 打開 思考 java 服務器 開發環境 首先思考java開發環境需要些什麽? 1、適用於我們開發環境的jdk 2、對應開發環境的IDE 3、如果是web應用,還需要web服務器,常用的有Tomcat 1) 下載對應組件 2) 安裝

Java開發之深入剖析Netty框架源碼實戰視頻教程

應用 pipe 事件處理 recycle 源碼 詳細分析 netty flush sel 第1章 課程介紹介紹本課程需要的前提知識和內容概要 第2章 Netty基本組件使用一個簡單的socket例子概括Netty裏面的基本組件,包括NioEventLoop,Channel,

我的第一個python web開發框架(24)——系統重構與ORM

內容 版權 質量 重寫 很多 掌握 orm .... 最重要的   小白弄完代碼版本管理和接口文檔後,興奮的找到老菜。   小白:老大,我已經按你講的要求,將代碼版本管理和接口文檔都搞好了。從項目開始到現在,除了代碼編寫,感覺學會好多東西啊。   老菜:嗯嗯,實戰確實需

JAVA開發血淚之路:一步步搭建spring框架

適配 param 實例 list ans oca 容器管理 simple inf 前言 作為一個服務端開發感覺一直挺排斥框架這種東西的,總覺得什麽實現邏輯都幫你封裝在裏面了,你只需要配置這配置那個,出了問題也不知道怎麽排查,之前即使寫web程序也寧願使用jetty這樣的嵌入