1. 程式人生 > >JMockit實踐--(1)入門簡介

JMockit實踐--(1)入門簡介

宣告:

Author:趙志乾

Date:2017-8-5

Declaration:All Right Reserved!!!


    1、本系列教程主要是介紹JMockit庫中一些註解和API的使用,這些註解和API能夠簡化測試用例的編寫。首先是能夠使被測物件自動例項化和初始化的註解;之後是模擬依賴的ExpectationsAPI;最後是仿造應用的mockupAPI(簡化外部元件的模擬)。

     注:該教程只是對JMockit庫中一些常用的註解、API、類進行簡單例項,詳細內容請參考API文件手冊。

    2、開發人員通常需要自己藉助一些測試框架(如JUnit)來寫一些驗證自己程式碼邏輯的測試用例。而自動化測試由可分為兩類:一類是對從系統中分割出來的類或者元件進行測試的單元測試,另一類是對系統操作進行測試的整體測試(一次涉及多個單元)。

    整體測試會涉及到多個元件或單元的互動,而通常在測試過程中我們感興趣的並不是所有的單元、元件或子系統,此時就需要對那些不感興趣的元件進行模擬或仿製,從而從系統中分離出我們感興趣的程式碼進行測試。因此,能夠“將程式碼從系統中進行分離”這種特性非常有用,但是,在實際使用中,我們要儘量保證測試環境的真實性,也就是說在理想情況下,應該使模擬或者仿製的部分壓縮到最小。

    3、通常而言,一個mock出來的物件是在單一測試或多個相關測試過程中對某個類的特定實現,它會在測試過程取代依賴物件,並且表現出預期的行為。但是這並不是mock物件唯一的能力,因為mock物件本身也可進行一些斷言。JMockit優於傳統mock物件的方面是:其支援在非模擬類上直接mock方法和建構函式,避免了測試過程中對mock物件進行例項化的需求。並且在測試過程,真實類上被模擬的方法和建構函式何時被呼叫,其都會表現出我們預定義的行為。而當一個類被模擬的時候,測試期間,模擬程式碼會取代原有程式碼。這些模擬方式不僅適用於例項方法,也適用於靜態方法、final方法和建構函式。

    注:mcok不僅適用於單元測試,也適用於整體測試。

   4、示例演示:

    假定我們有一個業務服務類,其遵循以下步驟來完成業務操作:

        取出某個持久化的實體;

        將實體的新狀態進行持久化;

        向某個需要感知該操作的元件傳送郵件進行告知;

    前兩個步驟需要訪問應用的資料庫,這通常會使用持久化子系統的簡化API來做,這裡使用的JPA。而最後一步需要使用第三方的API來發送郵件(示例中使用的是Apache的)。可以看出,這個服務類有兩個依賴,一個用於資料持久化、另一個用於傳送郵件。為了測試業務操作,我們會使用JMockit的JPA來處理持久化操作,而傳送郵件則使用模擬的API來完成。被測類的原始碼如下:

package tutorial.domain;

import java.math.*;
import java.util.*;
import org.apache.commons.mail.*;
import static tutorial.persistence.Database.*;

public final class MyBusinessService
{
   private final EntityX data;

   public MyBusinessService(EntityX data) { this.data = data; }

   public void doBusinessOperationXyz() throws EmailException
   {
      List<EntityX> items =
(1)      find("select item from EntityX item where item.someProperty = ?1", data.getSomeProperty());

      // Compute or obtain from another service a total value for the new persistent entity:
      BigDecimal total = ...
      data.setTotal(total);

(2)   persist(data);

      sendNotificationEmail(items);
   }

   private void sendNotificationEmail(List<EntityX> items) throws EmailException
   {
      Email email = new SimpleEmail();
      email.setSubject("Notification about processing of ...");
(3)   email.addTo(data.getCustomerEmail());

      // Other e-mail parameters, such as the host name of the mail server, have defaults defined
      // through external configuration.

      String message = buildNotificationMessage(items);
      email.setMsg(message);

(4)   email.send();
   }

   private String buildNotificationMessage(List<EntityX> items) { ... }
}

    資料庫類只包含一些靜態方法和一個私有的建構函式,而find和persist方法的意義很明確,此處將不再進行說明。那麼接下來我們要考慮如何在不修改原有程式碼的情況下來測試doBusinessOperationXyz這個方法?下面是JUnit的測試類,其中測試將會驗證持久化操作執行情況以及傳送郵件API的呼叫情況。這些驗證點位於上面示例程式碼中的數字標識位置。

package tutorial.domain;

import org.apache.commons.mail.*;
import static tutorial.persistence.Database.*;

import org.junit.*;
import org.junit.rules.*;
import static org.junit.Assert.*;
import mockit.*;

public final class MyBusinessServiceTest
{
   @Rule public final ExpectedException thrown = ExpectedException.none();

   @Tested final EntityX data = new EntityX(1, "abc", "[email protected]");
   @Tested(fullyInitialized = true) MyBusinessService businessService;
   @Mocked SimpleEmail anyEmail;

   @Test
   public void doBusinessOperationXyz() throws Exception
   {
      EntityX existingItem = new EntityX(1, "AX5", "[email protected]");
(1)   persist(existingItem);

      businessService.doBusinessOperationXyz();

(2)   assertNotEquals(0, data.getId()); // implies "data" was persisted
(4)   new Verifications() {{ anyEmail.send(); times = 1; }};
   }

   @Test
   public void doBusinessOperationXyzWithInvalidEmailAddress() throws Exception
   {
      final String email = "invalid address";
      data.setCustomerEmail(email);
(3)   new Expectations() {{ anyEmail.addTo(email); result = new EmailException(); }};
      thrown.expect(EmailException.class);

      businessService.doBusinessOperationXyz();
   }
}

    上面的示例中使用了JMockit的一些註解:其中@Tested註解會正確的初始化被測物件,@Mocked註解則用於模擬一個給定的型別。

    在測試類示例中,expectations的錄製(位於new Expectations() {{ ... }}中)和驗證(位於new Verifications() {{ ... }}中)在模擬型別或者例項上的對應方法被呼叫時會起作用。其中,對於返回值或異常丟擲都是通過欄位result進行指定,而呼叫次數則通過欄位times進行指定。

注:本部落格中的例項程式碼均來自於JMockit官方教程。

相關推薦

JMockit實踐--1入門簡介

宣告: Author:趙志乾 Date:2017-8-5 Declaration:All Right Reserved!!!     1、本系列教程主要是介紹JMockit庫中一些註解和

PHP入門1PHP簡介及常用工具

簡介 PHP(外文名:PHP: Hypertext Preprocessor,中文名:“超文字前處理器”)是一種通用開源指令碼語言,主要適用於Web開發領域。 特性(不限於以下幾點) (1)易學。由於PHP 獨特的語法混合了 C、Java、Perl 以及 PHP 自創新的語法,

企業級Redis開發運維從入門實踐 1—Redis 初識

Redis是什麼 Redis是一個開源、基於鍵值的儲存服務系統,具有多種資料結構,同時具有高效能、功能豐富(即高效能Key-Value、多種資料結構、豐富的功能、高可用分散式支援的資料儲存服務)的特性

C#刷遍Leetcode面試題系列連載1 - 入門與工具簡介

目錄 為什麼要刷LeetCode 刷LeetCode有哪些好處? LeetCode vs 傳統的 OJ LeetCode刷題時的心態建設 C#如何刷遍LeetCode 選項1:

Docker從入門實踐1

一、Docker簡介 1.1、什麼是 Docker   Docker 最初是 dotCloud 公司創始人 Solomon Hykes 在法國期間發起的一個公司內部專案,它是基於 dotCloud 公司多年雲服務技術的一次革新,並於&nbs

ArcGIS Pro 簡明教程1Pro簡介

配置 動畫 name app 產品 版本 鼠標拖動 nal mage ArcGIS Pro 簡明教程(1)Pro簡介 轉載地址:http://www.cnblogs.com/lazygis/p/5870545.html ArcGIS Pro 簡明教程(1)Pro簡

軟件工程綜合實踐1

creat from tro log ble nav .com jdbc logs 軟件工程綜合實踐(1) 1.學習回顧 mysql 使用 a. sql 文的使用(增、刪、改、查詢) 創建數據庫 mybatis a1. 表的創建 保存的表名 user

Openstack實踐1安裝部署第一個實例及neutron網絡

ipv6 dir hostname 鏈接 segment 訪問外網 繼續 過程 命名 版權聲明:本文為博主原創文章,歡迎轉載,轉載請註明作者、原文超鏈接 ,博主地址:http://www.cnblogs.com/SuperXJ/ 如何快速部署使用op

React技術實踐1

透明度 weex 常用 lar evel 目的 模塊 nat name 隨著系統越來越龐大,前端也變得越來越復雜,因此,構建一套組件化的前端變得很重要了。 之前一直在使用Asp.net來進行前端的組件化,Asp.net組件化有個很大的缺陷,就是和後臺代碼綁定太緊密了,不符合

1MFC簡介及MFC Object與Windows Object之間的比較

libraries 並且 bsp 應用 ets 銷毀 靈活 eight 公司 MFC(微軟基礎類庫)   微軟基礎類庫(Microsoft Foundation Classes,簡稱MFC)是微軟公司提供的一個類庫(class libraries),以C++類的形式封裝了W

Spring框架學習1Spring簡介

校驗和 遵從 直接 特定 cto 適合 配置 有意 允許 內容源自:Spring 框架簡介 Spring 是一個開源框架,是為了解決企業應用程序開發復雜性而創建的。框架的主要優勢之一就是其分層架構,分層架構允許您選擇使用哪一個組件,同時為 J2EE 應用程序開發提供集成的框

框架綜合實踐1-driver的封裝capability

讀取yaml配置檔案: 有兩種方式,一個是file open,一個是with open 方式1 file = open('../config/WiFibanlv_caps.yaml', 'r') data = yaml.load(file) file.close() #必須使用clo

Kettle 使用教程1入門

大資料的開發過程中使用的是Kettle為6.1.0版本 簡介 Kettle是一款純Java開發的ETL工具,它是跨平臺的,所以它可以在Window、Linux、Unix上執行。注意什麼是ETL,讀者可以自行百度瞭解,我的理解是將一個數據庫的資料匯入到另外一個數據庫中,

GloVe模型的理解及實踐1

一、GloVe模型的理解 1) 原理 功能:基於語料庫構建詞的共現矩陣,然後基於共現矩陣和GloVe模型對詞彙進行向量化表示 輸入:語料庫  輸出:詞向量 2)與Skip-Gram、CBOW模型比較 例如:句子為"dog barked at the mailman" ,目標

RabbitMQ學習筆記1----RabbitMQ簡介與安裝

·1. 什麼是RabbitMQ?   RabbitMQ是流行的開源訊息佇列系統,用erlang語言開發。RabbitMQ是AMQP(高階訊息佇列協議)的標準實現。   而AMQP協議則是指:即Advanced Message Queuing Protocol,一個提供統一訊息服務的應用層標準高階訊息佇列協

3D引擎資料結構與glTF1簡介

不是有句老話講“程式 = 演算法 + 資料結構”嘛,對於3D引擎來說也是這樣。學習和掌握3D引擎中的核心資料有哪些,它們直接的關係是怎樣等等問題,對於理解3D引擎的架構和圖形渲染關係都有著非常大的幫助。然而,現在的商業3D引擎非常複雜,想要通過學習其原始碼嘛非常困難,那麼你就這樣放棄了嗎

SpringBoot整合Spring Security1——入門程式

因為專案需要,第一次接觸Spring Security,早就聽聞Spring Security強大但上手困難,今天學習了一天,翻遍了全網資料,才僅僅出入門道,特整理這篇文章來讓後來者少踩一點坑(本文附帶例項程式,請放心食用) 本篇文章環境:SpringBoot 2.0 + Mybatis + S

Service Worker學習與實踐——PWA簡介

這周,Chrome 70正式版本釋出,Progressive Web Apps(PWA)已經正式支援到Windows 10平臺,然而,早在前幾個版本之前,Chrome就已經通過chrome://flags支援開啟實驗性的功能,早就支援在Windows 10平臺上安裝Progressive Web App

Go語言學習筆記1——入門

GO語言的基礎部分包括以下幾個成分: 包宣告 引入包 函式 變數 語句&表示式 註釋 一個簡單的go程式例子如下: package main //包名 import "fmt" //輸出包名,fmt包是實現了格式化IO的函式

RobotFramework自動化測試框架1- RobotFramework簡介

 對於RobotFramework自動化測試框架,我這裡會從三個單元進行闡述,希望能對你有幫助。 RobotFramework簡介 RobotFramework是什麼? Robotframework 是由python編寫的,一個開源的基於關鍵詞驅動的自動化測試框架,它可以做基於UI或者介面