1. 程式人生 > >Jmockit示例三部曲之二讓我驗證下你是否走對了

Jmockit示例三部曲之二讓我驗證下你是否走對了

上一章節我們主要講的是在執行test case之前,在recorded階段進行“期望”(可能會有些看不懂這個“期望”,實際上就是指對被mock的方法進行錄製,希望被引用的方法返回自己設定的值,或者欄位設定為自己設定的值)。這些“期望”是否真的在test case執行時發生了?一種是隱性的驗證(如果是嚴格的型別,即在Expectations block中,或者是進行了引用次數times的限制,如果這些“期望”沒有執行或者被引用的話,那麼就會報AssertionError),另一種就是沒有根本沒有進行驗證(如果是非嚴格型別,並且沒有進行引用次數times的限制),當然第二種方式是不提倡的。

接下來我們將介紹使用Jmockit提供的第二種型別的mock API——Jmockit Verifications API,它允許我們使用顯示的方式來驗證在test case執行的時候,我們所期望的mock是否真的被引用了。

被測類依舊是序言中的MyBussinessService類,先將官網上的程式碼貼上,然後一起理解

package jmockit.tutorial.domain;

import java.util.*;
import static java.util.Arrays.*;
import org.apache.commons.mail.*;
import jmockit.tutorial.persistence.*;

import org.junit.*;
import mockit.*;

public final class MyBusinessService_VerificationsAPI_Test
{
   @Tested MyBusinessService service; // instantiated automatically
   @Mocked(stubOutClassInitialization = true) Database onlyStatics;
   @Capturing Email email; // concrete subclass mocked on demand, when loaded

   final EntityX data = new EntityX(5, "abc", "
[email protected]
"); @Test public void doBusinessOperationXyzPersistsData() throws Exception { // No expectations recorded in this case. service.doBusinessOperationXyz(data); (2) new Verifications() {{ Database.persist(data); }}; } @Test public void doBusinessOperationXyzFindsItemsAndSendsNotificationEmail() throws Exception { // Invocations that produce a result are recorded, but only those we care about. new NonStrictExpectations() {{ (1) Database.find(withSubstring("select"), (Object[]) null); result = asList(new EntityX(1, "AX5", "
[email protected]
")); }}; service.doBusinessOperationXyz(data); new VerificationsInOrder() {{ (3) email.addTo(data.getCustomerEmail()); (4) email.send(); }}; } }
概括的說來,non-strict expectations相比較於strict expectations的不同之處在於:在test case的程式碼中,他可以被執行過,也可以不被執行,即使他們沒有事先進行record,並且如果不是特別要求,他們被引用的順序也是無關緊要的。

通過上面的例子指出,有兩種方式可以使我們進行的“期望”是non-strict expectations型別的:第一種,就是乾脆不要任何expectation block,就像第一個測試方法一樣(doBussinessOperationXyzPersistsData());第二種就是在一個NonStrictExpectations block中進行指定“期望”,第二個測試方法就是一個例子。在第一個測試例子中,產品程式碼中被mock型別的所有呼叫都能被不限制的引用,但是non-void的方法根據自身的返回型別會預設返回一個合適的值(這個在後面的章節會提到),很顯然,這是不合適的,所以在一個expecation block裡面進行一些“期望”是有必要的。混合著使用嚴格型(strict-expectations)和非嚴格型(non-strict expectations)也是可以的,通過在被mock的型別前新增@NonStrict,或者在Expectations block中進行“期望”的時候使用notStrict方法。

當我們使用了non-strict expectations,在回放階段呼叫的被mock的方法或者建構函式是否真的走了我們的“期望”而不是程式碼的真實邏輯,是不會立即進行驗證的(除非顯示的使用了times等呼叫次數限制)。這些非嚴格型的呼叫,在錄製的時候被指定了一個特定的返回值,甚至是一個異常,在test case進行回放的時候都會產生作用。

事實是在non-strict expectations中進行顯示的錄製後允許測試方法通過了,就足以證明被測方法做的是正確的(因為在非嚴格型裡面進行顯示錄製,必定是錄製了返回值,甚至是指定了呼叫的次數,這就包括了驗證了),在第二個測試例子中,如果將result=asList(…………)給註釋掉,那麼這個test case很有可能會fail掉,因為當其他的函式或者型別需要用到這個result的時候(只是預設的值,可能不能滿足要求),或者是呼叫的驗證失敗了。在這個例子中,如果真的去掉了result=asList(…………),那麼一個額外email.setMsg(withNotEqual(""))驗證就需要新增到另外2個已有的驗證中間。然而,在很多情況下,你需要確定被錄製的引用至少被運行了1次,那麼我們可以通過在錄製的時候,使用minTimes=1來做到這一點。
non-strict expectations的另一個優勢是他們可以顯示的驗證測試方法是否正確。這些verifications和錄製有點像,但是是在Verification block中(或者像例子中的VerificationsInOrder,這個是Verification的子類,inorder表明是按照順序進行驗證的,順序錯了,test case就會fail掉,這個會在以後的章節進行介紹),這些驗證是在測試方法執行之後進行驗證的,也就是在回放階段結束之後。而有times(或者maxTimes,minTimes)的,是在回放階段就會進行驗證。

從語法上來說,一個verification block是很像一個expectation block的。次數的限制對於測試方法的驗證是很有用的,也是必須用的(要不然光mock了,測試通過了,進行錄製的方法到底有沒有執行都不知道),前面就提到過使用times,minTimes,以及maxTimes這三個欄位,例如,如果一個被mock類中的方法在測試方法中從來沒有被呼叫過,那麼使用times=0(或者如果願意使用maxTimes=0)來進行驗證是十分正確的。

例子中的程式碼宣告的型別,使用了新的方式(這裡只是簡單的介紹一下,詳細的會在以後進行補充,如果急切需要了解,可以參考官方的API):

 @Tested MyBusinessService service; // instantiated automatically
 @Mocked(stubOutClassInitialization = true) Database onlyStatics;
 @Capturing Email email; // concrete subclass mocked on demand, when loaded
@Tested是可以幫我們自動生成被測的例項,而@Capturing是能在使用的時候,自動載入子類,可以和上一章的例子進行比較,上一章使用的是:
 @NonStrict SimpleEmail email; // calls to setters are unimportant, so we make it non-strict
使用@Capturing可以mock介面以及其所有的實現類,可以通過其屬性classNames來指定特定的實現類進行mock,而不是其所有的實現類,在這一點上,可以和@Mocked進行比較,當我們使用@Mocked mock一個類時,其所有的父類(當然除了java.lang.Object)也都被mock了

Verfications API就簡單的介紹到這,預告Jmockit示例三部曲的第三部——按我自己的思路走。


相關推薦

Jmockit示例三部曲驗證是否

上一章節我們主要講的是在執行test case之前,在recorded階段進行“期望”(可能會有些看不懂這個“期望”,實際上就是指對被mock的方法進行錄製,希望被引用的方法返回自己設定的值,或者欄位設定為自己設定的值)。這些“期望”是否真的在test case執行時發生了

自定義spring boot starter三部曲:實戰開發

本文是《自定義spring boot starter三部曲》的第二篇,上一篇中我們通過學習spring cloud的starter,對spring boot的starter有了初步瞭解,也設計好了實戰內容,今天就來一起實現; 三部曲文章連結 《自定義spring boot

spring4.1.8初始化原始碼學習三部曲:setConfigLocations方法

本章是學習spring4.1.8初始化原始碼的第二篇,前一章《spring4.1.8初始化原始碼學習三部曲之一:AbstractApplicationContext構造方法》對AbstractApplicationContext的初始化做了分析,本章我們聚焦

maven構建docker映象三部曲:編碼和構建映象

在《maven構建docker映象三部曲之一:準備環境》中,我們在vmware上準備好了ubuntu16虛擬機器,並且裝好了docker、jdk8、maven等必備工具,現在我們來開發一個java web工程,再用docker-maven-plugin外掛來

DockerJava檔案上傳服務三部曲:服務端開發

本章是《Docker下Java檔案上傳服務三部曲》的第二篇,上一章《Docker下Java檔案上傳服務三部曲之一:準備環境》我們把客戶端準備好了,Tomcat容器也部署好了,今天就來開發和部署檔案服務的後臺應用吧; 本章實戰內容概要 本章要建立三個w

Docker的Spring Cloud三部曲:細說Spring Cloud開發

本文是《Docker下的Spring Cloud三部曲》系列的第二篇,詳細講解上一篇例項中用到的eureka、provider、consumer等三個應用的開發過程; 環境資訊 回顧一下實戰環境,如下圖: 原始碼地址 上圖的eureka、

elasticsearch實戰三部曲:文件操作

本文是《elasticsearch實戰三部曲》系列的第二篇,上一篇文章我們動手熟悉了索引相關的基本操作,現在一起來熟悉文件相關的操作; 系列文章連結 《elasticsearch實戰三部曲之一:索引操作》; 《elasticsearch實戰三部曲之二:文件操作》;

kubernetes的Nginx加Tomcat三部曲:細說開發

本文是《kubernetes下的Nginx加Tomcat三部曲》的第二章,在《kubernetes下的Nginx加Tomcat三部曲之一:極速體驗》一文我們快速部署了Nginx和Tomcat,達到以下效果: 本文我會詳細說明在kubernetes部署上述網

實戰maven私有倉庫三部曲:上傳到私有倉庫

在上一章《實戰maven私有倉庫三部曲之一:搭建和使用》我們搭建了maven私有倉庫,並體驗了私有倉庫快取jar包的能力,避免了局域網內開發人員去遠端中央倉庫下載的痛苦等待,本章我們再來體驗私有倉庫的另一個功能:儲存二方庫; 使用場景 mvndemos

Dockerdubbo開發,三部曲:本地環境搭建

在上一篇文章《Docker下dubbo開發,三部曲之一:極速體驗》中,我們快速體驗了dubbo服務的註冊、發現、呼叫,今天我們一起在本地製作一套這樣的環境,經過這次實戰,大家就可以根據實際需求對自己的環境量身定製了。 基礎架構 整個環境由四個容器組成,梳

Docker實戰zabbix三部曲:監控其他機器

在上一章《Docker下實戰zabbix三部曲之一:極速體驗》中,我們快速安裝了zabbix server,並登入管理頁面查看了zabbix server所在機器的監控資訊,但是在實際場景中,應該是對應用伺服器做監控,所以今天我們來實戰將應用伺服器的監控加入到zabbix server中。 全系列文章連結:

CDH5部署三部曲:部署和設定

### 歡迎訪問我的GitHub [https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) 內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等; ### 本

Flink on Yarn三部曲:部署和設定

### 歡迎訪問我的GitHub [https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) 內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等; 本文是《

CDH+Kylin三部曲:部署和設定

### 歡迎訪問我的GitHub [https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) 內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等; ###

Flink的DataSource三部曲:內建connector

### 歡迎訪問我的GitHub [https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) 內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等; ###

CoProcessFunction實戰三部曲:狀態處理

### 歡迎訪問我的GitHub [https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) 內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等; ###

刨根究底字符編碼——關鍵術語解釋()

進行 過程 gb2312 sca 對象 編碼規則 繼續 bre 不一定 關鍵術語解釋(下) 一、第1層 抽象字符表ACR (Abstract Character Repertoire抽象字符清單):明確字符的範圍(即確定支持哪些字符) 1. 抽象字符表ACR是一個編碼

來告訴零下40度到底有多冷!

blank round -c span ont ans 12px color style http://neihanshequ.com/p76700993002/讓我來告訴你零下40度到底有多冷!

幾個每次都崩潰的Java概念——面向象什麽的,最可惡

ron ava 是個 實現 無法 對象 測試題 private clas 自制測試題 【填空題】 【選擇題】 【問答題】 (abstract方法)抽象方法可以用private來聲明嗎? 不能,抽象方法——最實質的意義/目的在於:被未來的子類方法覆

IT界的新方向-大數據?來告訴如何從“零”學起!

大數據學習+Java大數據行業目前炒的很是火爆,但是大數據的發展依然並不是很成熟,尤其是對於一些小白。了解系統的學習大數據的方法將更有利於自己更加快速有效的去學習大數據。分享一下零基礎如何學習大數據。 第一、對於初學者尤其是編程小白,Linux、Java的學習是必須的。但這並不代表我們非要研究透這些,我們只要