什麼是Moq Moq是一個框架,一個可以模擬對象的框架,比如在不實現介面的情況下獲得介面的對象,這個介面的所有行為都可以用代碼控制 快速開始 被模擬的可以是介面和類,類不能是密封類,只有類中的虛函數能被模擬 先寫一個介面,下麵例子大部分用這個介面,但不全用這個介面 當不用 時候 Throws Moc ...
什麼是Moq
Moq是一個框架,一個可以模擬對象的框架,比如在不實現介面的情況下獲得介面的對象,這個介面的所有行為都可以用代碼控制
快速開始
被模擬的可以是介面和類,類不能是密封類,只有類中的虛函數能被模擬
先寫一個介面,下麵例子大部分用這個介面,但不全用這個介面
public interface IDemo
{
int GetInt(int value);
string GetString(string value);
int Prop { get; set; }
}
//創建模擬對象
Mock<IDemo> mock = new Mock<IDemo>();
//開始設置這個對象的行為
//選擇要模擬的方法
mock.Setup(o => o.GetInt(It.IsAny<int>()))//設置給Get傳入任意int類型值時候才應用該行為
.Returns<int>(o => o);//Func<int,int>第一個是傳入參數類型,第二個是返回數據類型,設置把傳入參數原樣返回
var obj = mock.Object;
var result=obj.GetInt(1);
Assert.AreEqual(1, result);
當不用It.IsAny<int>()
時候
Mock<IDemo> mock = new Mock<IDemo>();
mock.Setup(o => o.GetInt(3))//設置給Get傳入3才應用該行為
.Returns<int>(o => o);//Func<int,int>第一個是傳入參數類型,第二個是返回數據類型,設置把傳入參數原樣返回
var obj = mock.Object;
var result=obj.GetInt(1);//這裡不傳入3
Assert.AreEqual(1, result);//測試失敗,result實際為0
Throws
mock.Setup(o => o.GetInt(3))
.Throws(new Exception("參數不能為空!"));
Mock
構造函數
public Mock();
public Mock(MockBehavior behavior);
public Mock(params object[] args);//arges,如果mock了一個類,可以為其構造函數傳入參數
public Mock(MockBehavior behavior, params object[] args);
MockBehavior
public enum MockBehavior
{
//
// 摘要:
// 如果被調用方法沒被setup調用的時候回拋異常
// Causes the mock to always throw an exception for invocations that don't have
// a corresponding setup.
Strict = 0,
//
// 摘要:
// 絕不拋異常,必要時返回預設值(引用類型返回null,值類型返回0,空數組或枚舉器)
// Will never throw exceptions, returning default values when necessary (null for
// reference types, zero for value types or empty enumerables and arrays).
Loose = 1,
//
// 摘要:
// 預設值,效果與Loose一樣
// Default mock behavior, which equals Moq.MockBehavior.Loose.
Default = 1
}
MockRespository
繼承MockFactory
故名思議一個工廠,這樣直接用工廠批量來創建對象,而不是一個個new
var factory = new MockRespository(MockBehavior.Strict);
//創建一個Mock
var aMock = factory.Create<IDemo>();
//等效於
var aMock=new Mock<IDemo>(MockBehavior.Strinct);
It
案例見文章開頭
方法 | 描述 |
---|---|
Is<T>(Expression<Func<T, bool>> match) |
指定參數必須符合match |
IsAny<T>() |
指定參數可以是任意值 |
IsRange<T>(min,max,kind) |
指定參數需要在指定範圍內,kind可以是Inclusive或Exclusive |
IsRegex(string regex) |
指定傳入的字元串必須符合regex表示的正則 |
這些方法的返回值都是T類型,它就像一個過濾器,只有傳入參數符合條件才把它返回
Match
當上述的It不能滿足需求的時候就用Match
T Match.Create<T>(System.Predicate<T>)
//傳入字元串不能為空
mock.Setup(o => o.GetString(Match.Create<T>(o=>!o.IsNullOrEmpty())))
Verification
驗證某個方法是否被調用了或是否被調用XX次,若沒有則拋出異常
Verify
mock.Setup(o => o.GetInt(It.IsAny<int>()))
.Returns<int>(o => o)
.Verifiable();//設置可驗證的
mock.Verify();
拋出異常MockVerificationException,因為我設定了GetInt是要驗證的,但是我並沒有調用它,所以執行最後一行Verify時候拋出了異常
註意沒有設置的Verifiable的方法不會被檢查.
Verify()是Mock的方法,還有一些帶參數的Verify屬於Mock<T>
mock.Verify(o=>o.GetInt(1),Times.Once());
驗證GetInt方法以1為參數調用一次
Times.Once()是靜態方法,除了可以用Once還可以用 AtLeast, AtLeastOnce, AtMost, AtMostOnce, Between, Equals, Exactly, Never
Property
模擬屬性
mock.Setup(o => o.Prop).Returns(111);
這跟模擬方法差不多,因為屬性的本質就是方法
快速設置
屬性有種簡寫方式,只是單純地保存數據
public T PropertyName{ get; set;}
這個SetupProperty可以模擬這個行為
mock.SetupProperty(o => o.PropertyName,DefaultValue);
Mock<IDemo> mock = new Mock<IDemo>();
mock.SetupProperty(o => o.Prop);
var obj = mock.Object;
obj.Prop = 111;
Console.WriteLine(obj.Prop);//輸出11
Mock<IDemo> mock = new Mock<IDemo>();
mock.SetupProperty(o => o.Prop,8888);
var obj = mock.Object;
Console.WriteLine(obj.Prop);//輸出8888
Callback
回調,故名思議但這個行為執行往後再執行的動作
mock.Setup(o => o.GetInt(2))
.Returns<int>(o => o)
.Callback<int>(o => { Console.Write(o); });
//當用模擬的對象調用GetInt且傳入參數為2的時候把參數2原樣返回
//然後執行回調函數,把輸入參數輸出到控制台
//不止一個地方能回調
mock.Setup(o => o.GetInt(2))
.Callback<int>(o => { Console.Write(o); });
.Returns<int>(o => o)
.Callback<int>(o => { Console.Write(o); });
Callback有多個重載
ICallbackResult Callback(Action action);
ICallbackResult Callback<T>(Action<T> action);
ICallbackResult Callback<T1, T2>(Action<T1, T2> action);
ICallbackResult Callback<T1, T2, T3>(Action<T1, T2, T3> action);
ICallbackResult Callback<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action);
ICallbackResult Callback<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action);
ICallbackResult Callback<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> action);
ICallbackResult Callback<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> action);
ICallbackResult Callback<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> action);
ICallbackResult Callback<T1, T2, T3, T4, T5, T6, T7, T8, T9>(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> action);
ICallbackResult Callback<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action);
ICallbackResult Callback<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> action);
ICallbackResult Callback<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> action);
ICallbackResult Callback<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> action);
ICallbackResult Callback<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> action);
ICallbackResult Callback<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> action);
ICallbackResult Callback<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16> action);