1.什么是Moq?
Moq是一個針對.Net開發的模擬庫,它從開始就充分利用了(Linq表達式)和(Lambda表達式)。它的目標是讓模擬以一種自然的方式與現有單元測試進行集成,使它更加簡單、直觀。使它成為了一個高生產力、類型安全、重構友好的模擬庫。
2.從哪得到Moq?
可以直接使用VS中的插件Nuget來獲取Moq並且引用到指定的項目。
3.Moq原理:
Moq使用Castle DynamicProxy完成這個任務。基本原理就是它利用反射機制的Emit功能動態生成一個空類型(也就是所有接口的方法都實例化,但是沒有任何功能,只是一個程序骨架)。所以Mock的能力就在於可以利用DynamicProxy的機制快速生產出一個假對象來,用於模仿真對象的行為。
4.Moq中的重要成員
(1).Mock:通過這個類,我們可以得到一個Mock<T>對象。T可以是接口,也可以是類。它有一個Public和Virtual屬性。比如:
定義一個接口界面:
public interface ITest
{
bool DoSomething(string actionname);
}
定義測試方法:
[TestMethod]
public void Test_Interface_ITest()
{
//創建Mock對象,偽造一個ITest的實現
var mo = new Mock<ITest>();
//設置模擬對象
mo.Setup(foo => foo.DoSomething("Ping")).Returns(true);(注意:Setup方法的參數是一個lambda表達式:可以這樣理解:當被模擬的對象foo調用它自己的方法Dosomething(),並且參數是Pring。添加后綴名Return(true)可以這樣理解:前邊的請求返回結果為真。這是指定的返回值。當一個請求調用DoSomething()方法時。如果傳入的參數是Pring,那么就返回true。然后添加一個斷言,去判斷是否能得到預期結果)
//斷言它
Assert.AreEqual(true, mo.Object.DoSomething("Ping"));
}
(2).It:這是一個靜態類,定義了靜態的泛型方法:
Is<TValue>、IsAny<TValue>、IslnRange<TValue>和IsRegex。去過濾參數。
(3)MockBehavior:這個類用於模擬對象的行為。就像是否按照默認的模式去模擬
(4)Verification:有時候,我們要確定一個方法是否被調用了,或者甚至要知道它被調用了多少次。就使用Verify()方法。;例如:
mock.Verify(foo=>foo.DoSomething(“Pring”),Times.Once())
上邊的代碼嘗試驗證DoSomething(“Pring”)需要被調用,並且只調用一次。出了Once選項,也有更多的選項可以選擇:如:Atleast(至少),AtLeastonce(至少一次),AtMost(最多),AtMostOnce(最多一次),Between(之間),Equals(等於),Exactly(確切的),Never(從未)和Once(一次)
5.功能點介紹
(1).帶有引用或輸出參數的方法。例如:
{方法:string GetAddress(string strUser, out string Address);
string GetFamilyCall(ref string strUser);}定義兩個方法
var customer = new Mock<ITest>();創建Mock對象,偽造一個ITest的實現
var outString="oo";
customer.Setup(p => p.GetAddress("", out outString)).Returns("sichuan");
customer.Setup(p => p.GetFamilyCall(ref outString)).Returns("xx");
(2)調用方法時拋出異常
方法:void ShowException(string str);
測試:var customer = new Mock<ITest>();
customer.Setup(p => p.ShowException(string.Empty))
.Throws(new Exception("參數不能為空!"));
customer.Object.ShowException("");
(3)Is<T>:匹配確定的給定類型
customer.Setup(x => x.SelfMatch(It.Is<int>(i => i % 2 == 0))).Returns("1");
方法SelfMatch接收int型的參數,當參數為偶數時,才返回字符串1.
(4)IsAny<T>:匹配給定的任何值
customer.Setup(p => p.SelfMatch(It.IsAny<int>())).Returns((int k) => "任何數:" + k);
方法SelfMatch接收int型,且任何int型參數都可以,然后返回:”任何數:”+K.
(5)IsInRange<T>:匹配給定類型的范圍
customer.Setup(p => p.SelfMatch(It.IsInRange<int>(0, 10, Range.Inclusive))).Returns("10以內的數");
方法SelfMatch接受int型,且當范圍在[0,10]時,才返回10以內的數
其中,這個方法,帶有一個包含與排除開關。
(6)IsRegex<T>:正則匹配
customer.Setup(p => p.ShowException(It.IsRegex(@"^\d+$")))
.Throws(new Exception("不能是數字"));
(7)Callbacks回調函數
當執行某方法時,調用其內部輸入的(Action)委托,有它的5種重載:
Callback(Action)
Callback<T>(Action<T>)
Callback<T1, T2>(Action<T1, T2>)
Callback<T1, T2, T3>(Action<T1, T2, T3>)
Callback<T1, T2, T3, T4>(Action<T1, T2, T3, T4>)
這個方法調用其內部輸入的Action委托,Aciton<T>有5種重載,所以這里的Callbacks有5種重載。
(8).Verify驗證
用於測試mock對象的方法或屬性是否被調用執行.也有很多重載:
Verify()
Verify(Expression<Action<T>>)
Verify<TResult>(Expression<Func<T, TResult>>)
Verify(Expression<Action<T>>, Times)
Verify(Expression<Action<T>>, String)
Verify<TResult>(Expression<Func<T, TResult>>, Times)
Verify<TResult>(Expression<Func<T, TResult>>, String)
Verify(Expression<Action<T>>, Times, String)
Verify<TResult>(Expression<Func<T, TResult>>, Times, String)
(9).VerifyAll驗證
在使用Verify方法時,只有被標記為可證實的(.Verifiable())的才可以驗證。