自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

測試中 Fakes、Mocks 以及 Stubs 概念明晰

開發(fā) 開發(fā)工具
在 securityOn 方法執(zhí)行之后,window 與 door 的 Mock 對象已經(jīng)記錄了所有的交互信息,這就允許我們能夠去驗(yàn)證 Window 與 Door 是否被真實(shí)的調(diào)用。

自動(dòng)化測試中,我們常會(huì)使用一些經(jīng)過簡化的,行為與表現(xiàn)類似于生產(chǎn)環(huán)境下的對象的復(fù)制品。引入這樣的復(fù)制品能夠降低構(gòu)建測試用例的復(fù)雜度,允許我們獨(dú)立而解耦地測試某個(gè)模塊,不再擔(dān)心受到系統(tǒng)中其他部分的影響;這類型對象也就是所謂的 Test Double。實(shí)際上對于 Test Double 的定義與闡述也是見仁見智,Gerard Meszaros 在這篇文章中就介紹了五個(gè)不同的 Double 類型;而人們更傾向于使用 Mock 來統(tǒng)一描述不同的 Test Doubles。不過對于 Test Doubles 實(shí)現(xiàn)的誤解還是可能會(huì)影響到測試的設(shè)計(jì),使測試用例變得混亂和脆弱,最終帶來不必要的重構(gòu)。本文則是從作者個(gè)人的角度描述了常見的 Test Doubles 類型及其具體的實(shí)現(xiàn):Fake、Stub 與 Mock,并且給出了不同的 Double 的使用場景。

[[191910]]

Fake

  • Fakes are objects that have working implementations, but not same as production one. Usually they take some shortcut and have simplified version of production code.Fake 是那些包含了生產(chǎn)環(huán)境下具體實(shí)現(xiàn)的簡化版本的對象。

如下圖所示,F(xiàn)ake 可以是某個(gè) Data Access Object 或者 Repository 的基于內(nèi)存的實(shí)現(xiàn);該實(shí)現(xiàn)并不會(huì)真的去進(jìn)行數(shù)據(jù)庫操作,而是使用簡單的 HashMap 來存放數(shù)據(jù)。這就允許了我們能夠在并沒有真的啟動(dòng)數(shù)據(jù)庫或者執(zhí)行耗時(shí)的外部請求的情況下進(jìn)行服務(wù)的測試。

  1. @Profile("transient"
  2. public class FakeAccountRepository implements AccountRepository { 
  3.  
  4.    Map<User, Account> accounts = new HashMap<>(); 
  5.  
  6.    public FakeAccountRepository() { 
  7.        this.accounts.put(new User("john@bmail.com"), new UserAccount()); 
  8.        this.accounts.put(new User("boby@bmail.com"), new AdminAccount()); 
  9.    } 
  10.  
  11.    String getPasswordHash(User user) { 
  12.        return accounts.get(user).getPasswordHash(); 
  13.    } 

除了應(yīng)用到測試,F(xiàn)ake 還能夠用于進(jìn)行原型設(shè)計(jì)或者峰值模擬中;我們能夠迅速地實(shí)現(xiàn)系統(tǒng)原型,并且基于內(nèi)存存儲(chǔ)來運(yùn)行整個(gè)系統(tǒng),推遲有關(guān)數(shù)據(jù)庫設(shè)計(jì)所用到的一些決定。另一個(gè)常見的使用場景就是利用 Fake 來保證在測試環(huán)境下支付永遠(yuǎn)返回成功結(jié)果。

Stub

  • Stub is an object that holds predefined data and uses it to answer calls during tests. It is used when we cannot or don’t want to involve objects that would answer with real data or have undesirable side effects.Stub 代指那些包含了預(yù)定義好的數(shù)據(jù)并且在測試時(shí)返回給調(diào)用者的對象。Stub 常被用于我們不希望返回真實(shí)數(shù)據(jù)或者造成其他副作用的場景。

Stub 的典型應(yīng)用場景即是當(dāng)某個(gè)對象需要從數(shù)據(jù)庫抓取數(shù)據(jù)時(shí),我們并不需要真實(shí)地與數(shù)據(jù)庫進(jìn)行交互或者像 Fake 那樣從內(nèi)存中抓取數(shù)據(jù),而是直接返回預(yù)定義好的數(shù)據(jù)。

  1. public class GradesService { 
  2.  
  3.    private final Gradebook gradebook; 
  4.  
  5.    public GradesService(Gradebook gradebook) { 
  6.        this.gradebook = gradebook; 
  7.    } 
  8.  
  9.    Double averageGrades(Student student) { 
  10.        return average(gradebook.gradesFor(student)); 
  11.    } 

我們在編寫測試用例時(shí)并沒有從 Gradebook 存儲(chǔ)中抓取數(shù)據(jù),而是在 Stub 中直接定義好需要返回的成績列表;我們只需要足夠的數(shù)據(jù)來保證對平均值計(jì)算函數(shù)進(jìn)行測試就好了。

  1. public class GradesServiceTest { 
  2.  
  3.    private Student student; 
  4.    private Gradebook gradebook; 
  5.  
  6.    @Before 
  7.    public void setUp() throws Exception { 
  8.        gradebook = mock(Gradebook.class); 
  9.        student = new Student(); 
  10.    } 
  11.  
  12.    @Test 
  13.    public void calculates_grades_average_for_student() { 
  14.        when(gradebook.gradesFor(student)).thenReturn(grades(8, 6, 10)); //stubbing gradebook 
  15.  
  16.        double averageGrades = new GradesService(gradebook).averageGrades(student); 
  17.  
  18.        assertThat(averageGrades).isEqualTo(8.0); 
  19.    } 

Command Query Separation

僅返回部分結(jié)果而并沒有真實(shí)改變系統(tǒng)狀態(tài)的的方法被稱作查詢(Query)。譬如 avarangeGrades,用于返回學(xué)生成績平均值的函數(shù)就是非常典型的例子:Double getAverageGrades(Student student);。該函數(shù)僅返回了某個(gè)值,而沒有其他的任何副作用。正如我們上文中介紹的,我們可以使用 Stubs 來替換提供實(shí)際成績值的函數(shù),從而簡化了整個(gè)測試用例的編寫。不過除了 Query 之外還有另一個(gè)類別的方法,被稱作 Command。即當(dāng)某個(gè)函數(shù)在執(zhí)行某些操作的時(shí)候還改變了系統(tǒng)狀態(tài),不過該類型函數(shù)往往沒有什么返回值:void sendReminderEmail(Student student);。這種對于方法的劃分方式也就是 Bertrand Meyer 在Object Oriented Software Construction 一書中介紹的 Command Query 分割法。

對于 Query 類型的方法我們會(huì)優(yōu)先考慮使用 Stub 來代替方法的返回值,而對于 Command 類型的方法的測試則需要依賴于 Mock。

Mock

  • Mocks are objects that register calls they receive. In test assertion we can verify on Mocks that all expected actions were performed.Mocks 代指那些僅記錄它們的調(diào)用信息的對象,在測試斷言中我們需要驗(yàn)證 Mocks 被進(jìn)行了符合期望的調(diào)用。

當(dāng)我們并不希望真的調(diào)用生產(chǎn)環(huán)境下的代碼或者在測試中難于驗(yàn)證真實(shí)代碼執(zhí)行效果的時(shí)候,我們會(huì)用 Mock 來替代那些真實(shí)的對象。典型的例子即是對郵件發(fā)送服務(wù)的測試,我們并不希望每次進(jìn)行測試的時(shí)候都發(fā)送一封郵件,畢竟我們很難去驗(yàn)證郵件是否真的被發(fā)出了或者被接收了。我們更多地關(guān)注于郵件服務(wù)是否按照我們的預(yù)期在合適的業(yè)務(wù)流中被調(diào)用,其概念如下圖所示: 

  1. public class SecurityCentral { 
  2.  
  3.    private final Window window; 
  4.    private final Door door; 
  5.  
  6.    public SecurityCentral(Window window, Door door) { 
  7.        this.window = window; 
  8.        this.door = door; 
  9.    } 
  10.  
  11.    void securityOn() { 
  12.        window.close(); 
  13.        door.close(); 
  14.    } 

在上述代碼中,我們并不想真的去關(guān)門來測試 securityOn 方法,因此我們可以設(shè)置合適的 Mock 對象:

  1. public class SecurityCentralTest { 
  2.  
  3.    Window windowMock = mock(Window.class); 
  4.    Door doorMock = mock(Door.class); 
  5.  
  6.    @Test 
  7.    public void enabling_security_locks_windows_and_doors() { 
  8.        SecurityCentral securityCentral = new SecurityCentral(windowMock, doorMock); 
  9.  
  10.        securityCentral.securityOn(); 
  11.  
  12.        verify(doorMock).close(); 
  13.        verify(windowMock).close(); 
  14.    } 

在 securityOn 方法執(zhí)行之后,window 與 door 的 Mock 對象已經(jīng)記錄了所有的交互信息,這就允許我們能夠去驗(yàn)證 Window 與 Door 是否被真實(shí)的調(diào)用?;蛟S有人會(huì)疑問是否在真實(shí)環(huán)境下門與窗是否被真的關(guān)閉了?其實(shí)我們并不能保證,不過這也不是我們關(guān)注的點(diǎn),也不是 SecurityCentral 這個(gè)類關(guān)注的目標(biāo)。門與窗是否能被正常的關(guān)閉應(yīng)該是由 Door 與 Window 這兩個(gè)類所關(guān)注的。

【本文是51CTO專欄作者“張梓雄 ”的原創(chuàng)文章,如需轉(zhuǎn)載請通過51CTO與作者聯(lián)系】

戳這里,看該作者更多好文

責(zé)任編輯:武曉燕 來源: 51CTO專欄
相關(guān)推薦

2009-07-09 17:09:49

MyEclipse

2010-01-19 17:23:11

TongWeb

2009-08-28 13:12:56

C#反射實(shí)例C#反射

2019-04-17 15:35:37

Redis數(shù)據(jù)庫數(shù)據(jù)結(jié)構(gòu)

2009-09-09 10:47:29

C# CheckBox

2010-08-14 21:59:35

2020-12-08 12:24:55

接口測試Interface

2012-05-29 09:42:08

Linux服務(wù)器窗口管理

2010-09-14 10:16:55

服務(wù)器虛擬化

2009-10-12 17:02:13

2009-12-25 15:36:29

雙線路接入技術(shù)

2017-04-28 14:25:06

支付卡合規(guī)方案

2009-09-04 17:53:51

C# Main函數(shù)

2021-08-06 06:38:49

安卓應(yīng)用Android 性能測試

2012-03-12 09:39:38

大數(shù)據(jù)IT資源

2011-05-20 17:59:06

回調(diào)函數(shù)

2009-09-11 03:21:00

網(wǎng)絡(luò)故障診斷

2013-07-29 10:27:19

2009-11-24 10:06:21

SUSE enterp

2009-09-01 11:10:00

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號