.net測試篇之Moq行為配置

  • 2019 年 10 月 3 日
  • 筆記

系列目錄

我們前面說過.Moq在創建模擬對象的時候,簡單對象賦值默認值,引用對象賦值為null,但是有些時候介面裡面還包含另一個介面對象,我們知道Moq是可以模擬一個介面對象的,我們可以通過配置讓Moq模擬所有可以Mock的對象.

我們新增如下程式碼

 public interface IDtoWrapper      {          MyDto Dto { get; set; }          string GetString();      }        public interface IOutString      {          IDtoWrapper wrapper { get; set; }        }

比如我們要模擬一個IOutString對象,如果不使用默認的行為則裡面的wrapper對象返回為Null,如果這樣我們沒法再繼續操作了.

我們可以對Moq的Default行為進行配置,讓它對IDtoWrapper對象也進行Mock

測試程式碼如下

       [Test]          public void BehaviorConfig()          {              var moq = new Mock<IOutString>();              moq.DefaultValue = DefaultValue.Mock;              Assert.NotNull(moq.Object.wrapper);          }

以上測試會通過.這時候wrapper不再是null,我們便可以對其進行操作了.

我們通過調試可以發現這時候不但IDtoWrapper不再是null,它裡面的Dto屬性也被賦值為一個new MyDto.是不是Mock框架可以模擬一個對象呢,實際上確實是可以,只不過是它模擬對象有很多限制,比如不能模擬不包含無參構造函數的對象,不能模擬不帶virtual或者abstract的方法等.如果我們對模擬的對象的方法沒有virual或者abstract修飾,這時候如果進行setup則會拋出異常.

前面我們講的如何通過配置使mock自動mock遇到到層級可Mock對象.這一節我們來看另一個問題.

假如有這樣一種場:要mock的介面里有一個Name屬性,在業務層我們要根據這個Name決定進入switch的不同分支裡面,但是回顧前面的章節,我們沒有遇到這種情況,我們都是只是在mock對象建立時使用setup為要mock的對象的欄位設置值.很多人可能會想,可以通過moq對象實體的Object屬性把這個對象拿出來,然後改變它的值.我們來看看這樣做可行不可行.

我們有以下一個簡單介面

  public interface ISt      {          string Name { get; set; }          int Age { get; set; }      }

測試方法如下

       [Test]          public void BehaviorConfig()          {              var moq = new Mock<ISt>();              var obj = moq.Object;              obj.Name = "baidu";              Assert.NotNull(moq.Object.Name);          }

我們把moq的Object對象賦值給obj,然後通過obj改變Name值.我們斷言moq.Object.Name的值不為null,不幸的是,測試沒有通過.

Avatar

按我們理解obj和moq.Object應該是引用類型,所以obj值的改變會引起moq.object值的改變,然而實際情況卻是我們一旦把moq.Objectm賦值給了obj,它們之間便脫離了關係.看來這樣是行不通的.

如何解決這個問題呢,其實moq實例對象裡面有一個SetupProperty方法,我們可以通過它來顯示指定哪些屬性會被跟蹤,如果屬性被跟蹤,則它的變化就會被記錄下來,而不像上面.

        [Test]          public void BehaviorConfig()          {              var moq = new Mock<ISt>();              moq.SetupProperty(a => a.Name);              var obj = moq.Object;              obj.Name = "baidu";              Assert.NotNull(moq.Object.Name);          }

我們多加了一行程式碼,測試便可以通過了.

但是如果屬性很多,這樣一行一行幾乎重複的程式碼挺煩的,moq實例裡面還有一個SetupAllProperties方法,這樣可以設置所有的屬性都被跟蹤.這樣如果多條需要這個值,我們便不需要每次都mock它,而只需要給它重新賦值即可.