![](/img/trans.png)
[英]NSubstitute's Received(count) is always green (when mocking concrete class)
[英]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
類的另一種方法是依賴為了測試這種方法,你可以只new
了Jeep
的實例,並通過它在這種情況下,你的測試; 因為它沒有任何過境行為(網絡呼叫等),所以不需要嘲笑它。 您可能還會考慮,如果是第二種情況,您應該能夠通過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.