簡體   English   中英

如何在模擬具體類時設置屬性

[英]How to setup property when mocking a concrete class

我試圖模擬(使用Moq)在第三方SDK中定義的類和接口。 以下是它們的簡單示例:

public interface IVehicle
{
    string Type { get; }
}
public class Vehicle
{
    public string Type { get; }
}
public class Jeep : Vehicle, IVehicle
{
}

我可以像這樣輕松地模擬界面:

var mockVehicle = new Mock<IVehicule>(MockBehavior.Strict);
mockVehicle
    .SetupGet(v => v.Type)
    .Returns("My custom vehicle");

但我需要編寫一個特定於Jeep類的單元測試,我無法弄清楚如何模擬它。

我的第一次嘗試:

var mockJeep = new Mock<Jeep>(MockBehavior.Strict);

產生了以下錯誤:

Moq.MockException: IVehicle.Type invocation failed with mock behavior Strict.
All invocations on the mock must have a corresponding setup.

這是可以理解的,因為我沒有設置Type屬性。

我的第二次嘗試:

var mockJeep = new Mock<Jeep>(MockBehavior.Strict);
mockJeep
    .SetupGet(v => v.Type)
    .Returns("Jeep");

產生以下錯誤消息:

System.NotSupportedException: Invalid setup on a non-virtual (overridable in VB) member: v => v.Type

這也是可以理解的,因為Vehicle類上的Type屬性不是虛擬的。

所以我的問題是:在模擬Jeep類時有沒有辦法設置Type屬性?

在這種情況下,最好的Moq可以創建一個代理作為Jeep的派生類,但它不能覆蓋非虛擬的Type屬性。 請記住,當您嘗試使用Moq創建Mock時,框架會生成一個類,該類可以實現目標接口,也可以從目標類派生。

Microsoft假裝您擁有Visual Studio許可級別來訪問它,可以很好地使用Moq。

由於這是一個相當普遍的問題,我將提出一個不同的方法。 模擬/偽裝/存取您無法控制的類或接口通常很困難。 此外,這通常會導致在模擬實例中復制其他人的功能。

更好的方法是將與外部庫的交互隔離到一個包裝類中,您可以控制它的接口和實現。 這將允許您輕松模擬/偽造/存根您的界面以測試您的界面的消費者。

這仍然留下了如何處理隔離層類的問題。 為此,您需要進行更多的集成測試,該測試實際上會運行您的包裝類和外部類。 然后,驗證您是否從您的類和要包裝的外部類的組合中獲得了預期的行為。

所以我的問題是:在模擬Jeep類時有沒有辦法設置Type屬性?

簡短的回答是否定的,你不能使用Moq模擬非虛擬成員。

但是,我不認為在這種情況下有任何理由來模擬任何東西,因為沒有任何行為可以模擬。 您擁有的唯一成員是一個簡單的string屬性。 所以,即使你可以,你也許不應該。

  • 如果您正在嘗試測試Jeep類,只需直接測試它而不會嘲笑其任何成員; 只有當您需要控制被測系統(SUT)的某個依賴項的行為時才應使用模擬
  • 如果你路過的Jeep類的另一種方法是依賴為了測試這種方法,你可以只newJeep的實例,並通過它在這種情況下,你的測試; 因為它沒有任何過境行為(網絡呼叫等),所以不需要嘲笑它。

您可能還會考慮,如果是第二種情況,您應該能夠通過IVehicle而不是Jeep ,在這種情況下, IVehicle會回到桌面上(盡管如上所述,在這種情況下沒有明顯需要)

順便提一下,你的層次結構看起來有點偏離 - 為什么Vehicle本身不會實現IVehicle

public interface IVehicle
{
    string Type { get; }
}
public class Vehicle: IVehicle
{
    public string Type { get; }
}
public class Jeep : Vehicle
{
}

那么Jeep已經既是車輛又是IVehicle :)

免責聲明:我在Typemock工作。

通過使用Typemock Isolator,您將能夠模擬非虛擬方法,並且不需要更改代碼,在此特定示例中,您可以偽造Jeep實例,然后修改其方法行為。
以下是模擬Jeep的測試示例:

[TestMethod]
public void CallFakeJeepType_WillReturnWantedString()
{
    var jeep = Isolate.Fake.Instance<Jeep>();
    Isolate.WhenCalled(() => jeep.Type).WillReturn("fake jeep");

    var result = Jeep.DoSomthing(jeep);

    Assert.AreEqual("fake jeep", result);
}

注意:如果Jeep.Type也有一個setter,你可以使用typemock的True屬性 ,測試看起來像這樣

    var jeep = Isolate.Fake.Instance<Jeep>();
    jeep.Type = "fake jeep";

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM