1. 程式人生 > >.net測試篇之Moq行為配置

.net測試篇之Moq行為配置

系列目錄

我們前面說過.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,不幸的是,測試沒有通過.

按我們理解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它,而只需要給它重新賦值即