成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

開發 開發工具
在 securityOn 方法執行之后,window 與 door 的 Mock 對象已經記錄了所有的交互信息,這就允許我們能夠去驗證 Window 與 Door 是否被真實的調用。

自動化測試中,我們常會使用一些經過簡化的,行為與表現類似于生產環境下的對象的復制品。引入這樣的復制品能夠降低構建測試用例的復雜度,允許我們獨立而解耦地測試某個模塊,不再擔心受到系統中其他部分的影響;這類型對象也就是所謂的 Test Double。實際上對于 Test Double 的定義與闡述也是見仁見智,Gerard Meszaros 在這篇文章中就介紹了五個不同的 Double 類型;而人們更傾向于使用 Mock 來統一描述不同的 Test Doubles。不過對于 Test Doubles 實現的誤解還是可能會影響到測試的設計,使測試用例變得混亂和脆弱,最終帶來不必要的重構。本文則是從作者個人的角度描述了常見的 Test Doubles 類型及其具體的實現: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 是那些包含了生產環境下具體實現的簡化版本的對象。

如下圖所示,Fake 可以是某個 Data Access Object 或者 Repository 的基于內存的實現;該實現并不會真的去進行數據庫操作,而是使用簡單的 HashMap 來存放數據。這就允許了我們能夠在并沒有真的啟動數據庫或者執行耗時的外部請求的情況下進行服務的測試。

  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.    } 

除了應用到測試,Fake 還能夠用于進行原型設計或者峰值模擬中;我們能夠迅速地實現系統原型,并且基于內存存儲來運行整個系統,推遲有關數據庫設計所用到的一些決定。另一個常見的使用場景就是利用 Fake 來保證在測試環境下支付永遠返回成功結果。

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 代指那些包含了預定義好的數據并且在測試時返回給調用者的對象。Stub 常被用于我們不希望返回真實數據或者造成其他副作用的場景。

Stub 的典型應用場景即是當某個對象需要從數據庫抓取數據時,我們并不需要真實地與數據庫進行交互或者像 Fake 那樣從內存中抓取數據,而是直接返回預定義好的數據。

  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.    } 

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

  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

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

對于 Query 類型的方法我們會優先考慮使用 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 代指那些僅記錄它們的調用信息的對象,在測試斷言中我們需要驗證 Mocks 被進行了符合期望的調用。

當我們并不希望真的調用生產環境下的代碼或者在測試中難于驗證真實代碼執行效果的時候,我們會用 Mock 來替代那些真實的對象。典型的例子即是對郵件發送服務的測試,我們并不希望每次進行測試的時候都發送一封郵件,畢竟我們很難去驗證郵件是否真的被發出了或者被接收了。我們更多地關注于郵件服務是否按照我們的預期在合適的業務流中被調用,其概念如下圖所示: 

  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.    } 

在上述代碼中,我們并不想真的去關門來測試 securityOn 方法,因此我們可以設置合適的 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 方法執行之后,window 與 door 的 Mock 對象已經記錄了所有的交互信息,這就允許我們能夠去驗證 Window 與 Door 是否被真實的調用?;蛟S有人會疑問是否在真實環境下門與窗是否被真的關閉了?其實我們并不能保證,不過這也不是我們關注的點,也不是 SecurityCentral 這個類關注的目標。門與窗是否能被正常的關閉應該是由 Door 與 Window 這兩個類所關注的。

【本文是51CTO專欄作者“張梓雄 ”的原創文章,如需轉載請通過51CTO與作者聯系】

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

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2009-07-09 17:09:49

MyEclipse

2010-01-19 17:23:11

TongWeb

2009-08-28 13:12:56

C#反射實例C#反射

2009-09-09 10:47:29

C# CheckBox

2019-04-17 15:35:37

Redis數據庫數據結構

2012-05-29 09:42:08

Linux服務器窗口管理

2010-09-14 10:16:55

服務器虛擬化

2010-08-14 21:59:35

2020-12-08 12:24:55

接口測試Interface

2017-04-28 14:25:06

支付卡合規方案

2009-09-04 17:53:51

C# Main函數

2009-12-25 15:36:29

雙線路接入技術

2009-10-12 17:02:13

2012-03-12 09:39:38

大數據IT資源

2021-08-06 06:38:49

安卓應用Android 性能測試

2013-07-29 10:27:19

2009-09-11 03:21:00

網絡故障診斷

2011-05-20 17:59:06

回調函數

2009-11-24 10:06:21

SUSE enterp

2019-09-10 11:34:23

軟件技術數據庫
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美片网站免费 | 91中文字幕在线 | 久久国产精品视频免费看 | 亚洲视频网 | 精品视频免费在线 | 婷婷免费视频 | 日韩午夜一区二区三区 | 久久新视频 | 日韩在线观看一区 | 欧美一区二区三区在线免费观看 | 秋霞电影一区二区三区 | 久久精品—区二区三区 | 国产黄色在线观看 | 日韩小视频在线 | 亚洲v区| 日韩午夜在线观看 | 日韩亚洲欧美综合 | 一区二区在线观看免费视频 | 精品国产乱码久久久 | 色爱综合网 | 涩涩视频在线观看 | 老司机67194精品线观看 | 天天色图 | 午夜视频网站 | 久久伊人久久 | 一级片av| 午夜精品一区二区三区在线观看 | 草草视频在线免费观看 | 久久av一区二区三区 | 一级片在线观看 | 狠狠夜夜| 久久激情视频 | 在线观看亚 | 中文字幕亚洲视频 | 狠狠操狠狠干 | 天堂在线免费视频 | 亚洲欧美国产精品一区二区 | 欧美h视频 | jlzzxxxx18hd护士| 欧美www在线观看 | 中文字幕一二三区 |