NSubstitute C#
▌背景
本篇練習NSubstitute的重點在於:
1. 在Unit Test中,如何Mock一些原始專案讀取內部資源(例如AppConfig)的方式。
這個專案的其中一個類別 PostCallbackRepositor提供一個方法 :
/// <summary>
/// 取得要Post Callback的Client Uri
/// <para>有效的Client Uri必須符合以下條件:</para>
/// <para>1.資料庫註記IsEnabled==true</para>
/// <para>2.不在Config設定的IP黑名單中</para>
/// </summary>
/// <returns>WebHookCallback
list</returns>
public IEnumerable<WebHookCallback>
GetClientUris()
|
所以在測試這個方法時,我們至少需要利用NSubstitute建立兩個Mock objects:
l 存取資料庫
l 存取Config
以正確的測試此方法。
▌相關文章
▌實作
▋Verify
the codes which you wanna test
上面提到我們要測試的程式碼如下:
public class PostCallbackRepository:IDisposable
{
private IAppconfigManager appconfigManagerNsub;
private IWebHookCallbackService whCallbackServiceNsub;
public PostCallbackRepository()
{
this.appconfigManagerNsub = new AppconfigManager();
this.whCallbackServiceNsub = new WebHookCallbackService();
}
/// <summary>
/// 取得要Post Callback的Client Uri
/// <para>有效的Client Uri必須符合以下條件:</para>
/// <para>1.資料庫註記IsEnabled==true</para>
/// <para>2.不在Config設定的IP黑名單中</para>
/// </summary>
/// <returns>WebHookCallback
list</returns>
public IEnumerable<WebHookCallback>
GetClientUris()
{
var entities =
whCallbackServiceNsub.Get(
x => !String.IsNullOrEmpty(x.Uri)
&&
x.IsEnabled == true).ToList();
for (int i= (entities.Count-1); i>=0;
i--)
{
if(this.chkIfLockedIp(entities[i].Uri))
{
entities.Remove(entities[i]);
}
}
return entities.AsEnumerable();
}
private bool chkIfLockedIp(String uri)
{
foreach(var lockedIp in appconfigManagerNsub.LockIPs)
{
if (uri.IndexOf(lockedIp) >= 0)
return true;
}
return false;
}
public void Dispose()
{
this.appconfigManagerNsub = null;
this.whCallbackServiceNsub = null;
}
}
|
PS. 在讀取Config的設定值這一段,如果沒有建立一個Interface來處理,則無法使用NSubstitute來處理,這邊是比較可能需要重構的地方。
By the way, 以下是資料表結構和Config檔的參考
▋Unit
Test
如前述,在測試代碼中,只要針對DAL和讀取Config的interfaces建立NSub Mock objects,並利用Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject注入, 即可順利進行測試。
相關說明可直接參考程式碼註解。
[TestMethod]
public void
TestTriggerCallback()
{
#region Create the Substitutes
//Create the Nsubs for the
interfaces
var appconfigManagerNsub = Substitute.For<IAppconfigManager>();
var whCallbackServiceNsub = Substitute.For<IWebHookCallbackService>();
#endregion
#region Set the return value of the mock
objects
var mockupClientUris = new List<WebHookCallback>() {
new WebHookCallback() {
WebHookCallbackId= 1, IsEnabled=true, Uri= "http://10.1.2.3:13050/api/Receive/Receive1" },
new WebHookCallback() {
WebHookCallbackId= 2, IsEnabled=true, Uri= "http://10.4.5.6:13050/api/Receive/Receive1" },
new WebHookCallback() {
WebHookCallbackId= 3, IsEnabled=true, Uri= "http://localhost:13050/api/Receive/Receive1" },
new WebHookCallback() {
WebHookCallbackId= 4, IsEnabled=true, Uri= "http://localhost:13050/api/Receive/Receive2" },
new WebHookCallback() {
WebHookCallbackId= 5, IsEnabled=true, Uri= "http://localhost:13050/api/Receive/Receive3" },
};
whCallbackServiceNsub.Get(
Arg.Any<Func<WebHookCallback, Boolean>>()).Returns(
mockupClientUris.AsQueryable());
appconfigManagerNsub.LockIPs.Returns(new String[] { "10.1.2.3", "10.4.5.6" });
#endregion
#region Intialize the test target
var pcbRepository =
new JB.Sample.WebHook.WebApi.PostCallbackRepository();
PrivateObject accessor = new PrivateObject(pcbRepository);
accessor.SetField("appconfigManagerNsub", appconfigManagerNsub);
accessor.SetField("whCallbackServiceNsub", whCallbackServiceNsub);
#endregion
#region Test Codes
IEnumerable<WebHookCallback>
actualWhCallbacks =
pcbRepository.GetClientUris().OrderBy(x=>x.WebHookCallbackId);
var expectedCnt = 3;
Assert.AreEqual(expectedCnt,
actualWhCallbacks.Count());
Assert.AreEqual(actualWhCallbacks.ElementAt(0).Uri,
mockupClientUris[2].Uri);
Assert.AreEqual(actualWhCallbacks.ElementAt(1).Uri,
mockupClientUris[3].Uri);
Assert.AreEqual(actualWhCallbacks.ElementAt(2).Uri,
mockupClientUris[4].Uri);
#endregion
}
|
測試結果 :
▌Reference
沒有留言:
張貼留言