集成測試主要是測試個元件之間的互動是否如預期,在這個階段的測試,我會把程式進入點 UI Layer 換成單元測試專案,由測試專案取代之,為什麼不是直接從UI測,原因很簡單,因為 UI 的變化太快了,一方面為了減少因 UI 改變而衍生出額外的工作,另一方面則為了提高測試程式碼的重用性,所以我會從 BLL 測試
三層式架構,物件彼此之間的關係,如下圖:
單元測試成為程式進入點,如下圖:
當測試會需要用到資料庫,就必須要讓 CI Server 也能順利的存取到資料庫,以便運行自動化測試,對資料庫的要求,
我需要:
- 測試資料庫已存在專案所需資料。
- 確保每次運行測試時,不會有人弄髒測試資料庫。
- 任何人拿從版控上拿到專案,不需要太多的設定就能運行任何測試。
- CI Server 也能運行測試。
我採用:
LocalDB,
原因一:VS 安裝時會一併安裝 LocalDB,開發人員不需要另外準備環境
- VS 2013 預設安裝 SQL Server 2012 Express LocalDB,預設執行個體名稱(localdb)\v11.0
- VS 2015 預設安裝 SQL Server 201 Express LocalDB,預設執行個體名稱(localdb)\MSSQLLocalDB
原因二:mdf 附加檔案很輕鬆
開發環境:
- VS 2015 Enterprise Update 1(內建SQL Server 2014 Express LocalDB)
- 保哥有寫一篇介紹有關 LocalDB 知識和管理,含金量很高,請參考:http://blog.miniasp.com/post/2012/09/03/SQL-Server-2012-Express-LocalDB-Quick-Start.aspx
- Entity Framework 6.1.3 from Nuget
- SQL Server 2104 Developer Edition
- Windows 10 x64 Enterprise
接著來看看我的專案分層結構,如下圖:
左邊的 Solution Explorer 是各個 Layer 的專案
右邊的Code Map可以看出專案彼此之間的相依關係,虛線代表專案參考,紅線代表呼叫
TestDB 專案:
- 提供給所有的測試專案使用
- 裝載著 mdf 檔案,這個檔案怎麼來?有兩種方式
- *.mdf 檔案設為 Copy if newer
IntegrateUnitTestProject 專案:
- 參考 TestDB 專案 ,取得 *.mdf
- LocalDB 連線字串
- 設定 DeploymentItem
- 設定 ClassInitialize
運行測試
[TestMethod]
public void BLL_TestMethod()
{
var expected = 2;
FlowBLL bll = new FlowBLL();
var members = bll.GetMembers();
var actual = members.Count();
Assert.AreEqual(expected, actual);
}
專案範本如下:
https://dotblogsamples.codeplex.com/SourceControl/latest#Simple.UnitTestAndLocalDB/
1.找出資料庫相對應的 mdf 檔案
2.讓資料庫離線
3.複製 *.mdf 到 VS 專案
指定資料庫名稱 Initial Catalog=TestDB ,這樣才不會在SSMS看到一堆沒有用的資料庫連線
<add name="DAL"
connectionString="Data Source=(LocalDB)\MSSQLLocalDB;
AttachDbFilename=|DataDirectory|\TestDB.mdf;
Initial Catalog=TestDB;
MultipleActiveResultSets=True;
Integrated Security=True;
App=EntityFramework"
providerName="System.Data.SqlClient" />
第一個參數:因為 TestDB 專案的 TestDB.mdf,放在 "App_Data" 目錄,輸出到 IntegrateUnitTestProject/bin 也仍然會維持相同結構,所以這裡要設定 "App_Data\\TestDB.mdf"
第二個參數:我想要讓 TestDB.mdf 存放在測試結果目錄的 "App_Data",所以這裡設定 "App_Data"
[TestClass]
[DeploymentItem("App_Data\\TestDB.mdf", "App_Data")]
public class UnitTes1
{
//...
}
測試專案的輸出目錄,他在方案目錄下的TestResults,每次運行測試,他會依時間產生目錄,目錄底下有 in/out 資料夾,如下圖:
DeploymentItem 會把 *.mdf 複製一份到 out 資料夾,也就是說在測試專案裡處理的資料不會弄髒 TestDB 專案的 TestDB.mdf,如下圖:
測試類別初始化,這裡要準備兩個動作
這是一個很神奇的寫法,缺了不會跑,如下代碼:
var instance = System.Data.Entity.SqlServer.SqlProviderServices.Instance;
這裡是在設定 DataDirectory 所對應到的 TestResults/out 目錄,DataDirectory 指的是連線字串裡的 |DataDirectory|
AppDomain.CurrentDomain.SetData(
"DataDirectory",
Path.Combine(context.TestDeploymentDir, "App_Data"));
完整程式碼:
[ClassInitialize]
public static void SetUp(TestContext context)
{
var instance = System.Data.Entity.SqlServer.SqlProviderServices.Instance;
AppDomain.CurrentDomain.SetData(
"DataDirectory",
Path.Combine(context.TestDeploymentDir, "App_Data"));
}
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET