STUB的功能
這邊是NSubstitute的說明:http://nsubstitute.github.io/help/getting-started/
Substitute是.NET裡的一個隔離框架,若要使用,需要額外在測試專案用NUGET去安裝NSubstitute
1. 動態產生假物件
2. 模擬回傳值
3. 測試監聽事件
4. 驗證傳入參數是否正確
使用Subsitute(Sub)
使用方法如下
calculator = Substitute.For
設定呼叫某個方法應該回傳的值
calculator.Add(1, 2).Returns(3);
Assert.That(calculator.Add(1, 2), Is.EqualTo(3));
下面可以驗證是否Add這個FUNC有被呼叫到
calculator.Add(1, 2);
calculator.Received().Add(1, 2);
calculator.DidNotReceive().Add(5, 7);
下面的程式能夠判別傳入的參數是不是正確
calculator.Add(10, -5);
calculator.Received().Add(10, Arg.Any
calculator.Received().Add(10, Arg.Is
.Returns(x => (int)x[0] + (int)x[1]);
Assert.That(calculator.Add(5, 10), Is.EqualTo(15));
使用Substitute來針對不同狀況實作假介面
這是一個用MOCK方法的範例
using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; //using Microsoft.VisualStudio.TestTools.UnitTesting; using NUnit.Framework; using RsaSecureToken; using Assert = NUnit.Framework.Assert; namespace RsaSecureToken.Tests { [TestFixture] public class AuthenticationServiceTests { [Test()] public void IsValidTest() { var target = new AuthenticationService(new FakeProfile(), new FakeToken()); var actual = target.IsValid("joey", "91000000"); //always failed Assert.IsTrue(actual); } } public class FakeProfile:IProfile { public string GetPassword(string account) { if (account == "joey") { return "91"; } throw new Exception(); } } public class FakeToken:IRsaToken { public string GetRandom(string account) { return "000000"; } } }
上面做法有什麼問題?
- 每一個不同的依賴案例就要製作一個不同的FakeObject,會讓寫測試的時間太久
- 沒辦法直接從程式碼知道為什麼這樣會是Vaild
動態產生物件的使用完整範例
Subsitute.For
定義假物件行為(stub)
fake.方法(參數).Returns(值)
[Test()]
public void IsValidTest()
{
var fakeProfile = Substitute.For
fakeProfile.GetPassword(“joey”).Returns(“91”);
var fakeToken = Substitute.For
fakeToken.GetRandom(“”).ReturnsForAnyArgs(“000000”);
var target = new AuthenticationService(fakeProfile, fakeToken);
var actual = target.IsValid(“joey”, “91000000”);
//always failed
Assert.IsTrue(actual);
}
}
驗證某個函數是否被呼叫
使用mock object assertion
需求:驗證是非法的時候要記一個log
fake.Receive(次數).方法(參數驗證)
不要用太多mock就算要使用要避免過度指定,也就是當prod code小小變動就導致測試程式壞掉
下面的程式碼可以驗證當呼叫SyncBookOrders()時是不是會呼叫Insert這個函數兩次:
[Test]
public void Test_SyncBookOrders_3_Orders_Only_2_book_order()
{
var result = new List
{
new Order
{
Type = “Book”
},
new Order
{
Type = “Book”
},
new Order
{
Type = “Item”
}
};
var target = new OrderServiceForTest();
target.SetOrder(result);
var fakeBookDao = Substitute.For
target.SetDao(fakeBookDao);
target.SyncBookOrders();
fakeBookDao.Received(2).Insert(Arg.Is
}
驗證傳入參數
驗證傳入的參數是否包含某些關鍵字
_logger.Received(1).Save(Arg.Is