第一篇文章, 關於Mock的概念介紹: http://www.javashuo.com/article/p-rjikmmye-ha.htmlhtml
第二篇文章, 關於方法Mock的介紹: http://www.javashuo.com/article/p-bbgioyks-mg.htmlgit
本文介紹Moq的使用.github
使用的代碼: https://github.com/solenovex/Moq4-Tutorial-Code 裏面的 03 Before 部分.單元測試
屬性是指 get set property.測試
接着上文, 我在03 Before部分的代碼裏作了一些修改.spa
首先IPhysicalExamination接口添加了IsMedicalRoomAvailable屬性:調試
其實現類:htm
屬性方法內依然沒有作實現.對象
添加的這個屬性在業務上的意思就是體檢室是否可使用. 若是不可使用的話, 那麼球員的轉會操做應該被推遲.blog
因此還須要爲轉會結果枚舉添加一個推遲:
最後在轉會審批邏輯裏進行判斷, 若是體檢室不可用, 那麼轉會就被推遲:
在單元測試裏對屬性進行mock很是的簡單:
這個測試也會經過的:
修改一下IPhysicalExamination接口, 造成一個多層嵌套的屬性:
IPhysicalExamination --> IMedicalRoom --> IMedicalRoomStatus --> IsAvailable.
經過上面這一串來判斷體檢室是否可用.
相應的實現類也要修改:
轉會審批方法裏也要修改:
而在單元測試的方法裏, 確定是報錯的:
按照正常的思路, 咱們可能會這樣作:
就是從內到外一層一層的mock.
這麼作是沒問題的, 測試也會經過:
可是這樣作很麻煩, 而Moq則提供了一種簡單的方式來處理這種多層的/遞歸的mock:
這樣寫便可. 測試一樣會經過:
可是, 問題來了, 我還有一些其它的單元測試方法, 它們也須要用到這個屬性, 如今它們的狀態是:
有的測試失敗是由於其MockBehavior是Strict的, 而其它的失敗則是由於裏面出現了NullReferenceException.
針對這些狀況, 咱們能夠這樣設定:
這樣設置以後, 它會返回屬性類型的默認值, 由於我沒有設定返回值.
雖然測試依然不經過, 這是由於邏輯上的問題, 而不會拋出異常:
針對這種狀況, 還有一種更好的辦法. 咱們能夠爲mock對象設定默認值:
把DefaultValue的值設爲DefaultValue.Mock.
可是DefaultValue這個屬性只對引用類型起做用(對值類型不起做用), 像這種遞歸的mock, 它會遞歸的建立所需的引用類型, 可是最後的IsAvailable這個值類型是不起做用的.
測試:
由於最後一層是bool類型的, 是值類型, 因此上面的設置不起做用, 返回的是false. 因此測試沒經過.
那我就把它改爲string類型好了:
審批方法:
而後再調試測試:
string是引用類型, 可是mock的值依然是null...??!!??
這是由於string是一個sealed class, 而DefaultValue.Mock只對接口, 抽象類和非sealed的class起做用....
不過測試仍然是能夠經過的, 由於我改邏輯了:
注意, 這個默認值只對寬鬆(Loose) mock, 起做用.針對Strict mock, 仍然須要設定最後一層屬性的值.
須要添加一些代碼, 首先添加一個枚舉:
爲接口添加屬性:
實現類:
而後在審批類裏, 我設置了這個屬性的值:
上面的代碼也就是說, 個人mock對象的某個屬性在測試的時候它的值會發生變化. 而Moq能夠記住這些mock屬性的變化的值.....
新寫一個測試:
這裏使用mockObj.SetupProperty()方法來開始追蹤屬性. 這個測試會經過:
該方法也能夠經過下面的寫法來爲被追蹤的屬性設置默認值:
mockExamination.SetupProperty(x => x.PhysicalGrade, PhysicalGrade.Failed);.
若是這個對象上有不少屬性須要進行設置和追蹤, 那麼可使用:
mock.SetupAllProperties(); 這個方法:
注意, 這個方法應該最早調用, 不然的話其它的設置可能會被覆蓋.
本文完成的代碼在: https://github.com/solenovex/Moq4-Tutorial-Code 裏面的03 After.
未完待續......