第一篇文章, 關於Mock的概念介紹: https://www.cnblogs.com/cgzl/p/9294431.html
第二篇文章, 關於方法Mock的介紹: https://www.cnblogs.com/cgzl/p/9300356.html
第三篇文章, 關於屬性Mock的介紹: https://www.cnblogs.com/cgzl/p/9304567.html
第四篇文章, 關於行為Mock的介紹: https://www.cnblogs.com/cgzl/p/9306728.html
本文介紹使用Moq其它一些功能.
使用的程式碼: https://github.com/solenovex/Moq4-Tutorial-Code 裡面的 05 Before 部分.
丟擲異常
這裡是指讓mock物件丟擲異常.
首先建立一個測試方法, 並設定球員年齡小於16歲時, IPhysicalExamination會在呼叫IsHealthy()方法時丟擲異常:
隨後在球員審批的方法裡, 需要捕獲這個異常, 並返回相應的結果:
這個測試會通過:
上面使用的是泛型的版本來丟擲異常, 也可以不使用泛型, 直接丟擲異常:
Events
我們還可以讓mock物件來引起事件.
首先在IPhysicalExamination新增一個event:
每當IsHealthy()方法被呼叫後, 就應該引起這個event事件.
在實現類裡, 也需要加上這個event, 但是暫時不對它做任何其它動作:
在轉會審批類裡, 做這樣幾處修改:
新增一個處理事件的方法, 如果事件被觸發, 那麼PlayerHealthChecked這個標識就會變成true.
建立一個測試方法, 以判斷該event是否被觸發:
這個測試應該會失敗:
因為該event並沒有被觸發(PhysicalExamination裡並沒做什麼動作).
這時, 我們可以使用mock物件來觸發該事件, 在測試方法裡, 手動呼叫mock物件的Raise()方法:
第一個引數是lambda表示式, 該事件繫結到null, 第二個引數針對本例是EventArgs.Empty即可.
再測試, 就會通過:
第二種方法是在設定IsHealthy()方法的時候對事件進行觸發設定:
這樣的話只要IsHealthy()方法被呼叫, 那麼HealthChecked這個事件也會被觸發.
該測試也會通過:
設定連續呼叫的不同返回值
使用SetupSequence()方法可以為mock物件的成員在連續呼叫的時候每次都返回指定的值(或丟擲指定的異常):
該測試執行時, 第一次呼叫IsHealthy()方法時, 該方法返回true, 體檢通過; 而第二次呼叫IsHealthy()方法時, 返回false, 體檢不通過.
這個測試是會通過的:
Mock 不實現介面的方法
首先建立一個類, 它沒有實現任何介面, 裡面有一個方法用於判斷當前是否處於轉會期:
然後在轉會審批類裡使用該類:
建立一個測試方法, mock上面的類:
但是該測試回失敗:
這是因為Moq在mock這種類的時候要求其方法必須是virtual的.
那麼修改該方法為virtual:
這樣的話測試就會通過:
Protected Virtual 方法
為上面的類再新增一個protected virtual 方法:
如果想要mock這個方法的話, 需要這樣用:
有引數的話, 需要用到ItExpr類.
Linq to Mocks
我們可以把之前寫的設定程式碼使用Linq的方式來寫:
這裡要使用Mock.Of<T>()方法. 引數的lambda表示式裡面可以設定mock物件成員的返回值.
由於這種方法直接返回所需的型別, 所以在使用mock物件的時候就無需使用.Object屬性了.
該測試也會通過:
Moq的簡介就到這裡, 其實看官方文件會更快速一些: https://github.com/Moq/moq4/wiki/Quickstart
重構後的程式碼在: https://github.com/solenovex/Moq4-Tutorial-Code 裡面的05 After.