您可以使用 Microsoft 單元測試架構 (MSTest) 為受控程式碼設定單元測試方法,以從資料來源擷取值。 方法會針對數據源中的每個數據列連續執行,這可讓您輕鬆地使用單一方法測試各種輸入。
資料驅動單元測試可以使用下列任何一種:
- 使用
DataRow
屬性的內嵌數據 - 使用
DynamicData
屬性的成員數據 - 從一些知名的來源提供者使用
DataSource
屬性
受測方法
例如,假設您有:
稱為
MyBank
的解決方案,可接受和處理不同類型的帳戶交易。MyBank
中稱為BankDb
的專案,可管理帳戶的交易。在
Maths
專案中稱為BankDb
的類別,會執行數學函式,以確保任何交易對銀行有利。稱為
BankDbTests
的單元測試專案,用來測試BankDb
元件的行為。稱為
MathsTests
的單元測試類別,用來驗證Maths
類別的行為。
我們將在 Maths
中測試使用 迴圈新增兩個整數的方法:
public int AddIntegers(int first, int second)
{
int sum = first;
for (int i = 0; i < second; i++)
{
sum += 1;
}
return sum;
}
測試測試方法
內嵌資料驅動測試
針對內嵌測試,MSTest 會使用 DataRow
來指定數據驅動測試所使用的值。 此範例中的測試會針對每個數據列連續執行。
[TestMethod]
[DataRow(1, 1, 2)]
[DataRow(2, 2, 4)]
[DataRow(3, 3, 6)]
[DataRow(0, 0, 1)] // The test run with this row fails
public void AddIntegers_FromDataRowTest(int x, int y, int expected)
{
var target = new Maths();
int actual = target.AddIntegers(x, y);
Assert.AreEqual(expected, actual,
"x:<{0}> y:<{1}>",
new object[] {x, y});
}
成員數據驅動測試
MSTest 會使用 DynamicData
屬性來指定成員的名稱、種類和定義類型(預設會使用目前類型),以提供資料驅動測試所使用的數據。
注意
在 MSTest 3.8 之前,DynamicDataSourceType
列舉有兩個成員,Property
和 Method
。 預設值為 Property
。 從 MSTest 3.8 開始,新的成員 AutoDetect
會新增至 列舉,而且是預設值。 因此,您不再需要指定 DynamicDataSourceType
。
public static IEnumerable<object[]> AdditionData
{
get
{
return new[]
{
new object[] { 1, 1, 2 },
new object[] { 2, 2, 4 },
new object[] { 3, 3, 6 },
new object[] { 0, 0, 1 }, // The test run with this row fails
};
}
}
[TestMethod]
[DynamicData(nameof(AdditionData))]
public void AddIntegers_FromDynamicDataTest(int x, int y, int expected)
{
var target = new Maths();
int actual = target.AddIntegers(x, y);
Assert.AreEqual(expected, actual,
"x:<{0}> y:<{1}>",
new object[] {x, y});
}
您也可以使用 DynamicData
屬性中的 DynamicDataDisplayName
屬性來更改預設生成的顯示名稱。 顯示名稱方法簽章必須 public static string
並接受兩個參數,第一個類型為 MethodInfo
,第二個類型 object[]
。
public static string GetCustomDynamicDataDisplayName(MethodInfo methodInfo, object[] data)
{
return string.Format("DynamicDataTestMethod {0} with {1} parameters", methodInfo.Name, data.Length);
}
[DynamicData(nameof(AdditionData), DynamicDataDisplayName = nameof(GetCustomDynamicDataDisplayName))]
來源提供者數據驅動測試
建立資料源驅動單元測試牽涉到下列步驟:
建立數據源,其中包含您在測試方法中使用的值。 數據源可以是在執行測試的計算機上註冊的任何類型。
將類型為
TestContext
的公用 TestContext 屬性新增至測試類別。建立單元測試方法
將 DataSourceAttribute 屬性新增至其中。
使用 DataRow 索引器屬性來擷取您在測試中使用的值。
注意
DataSourceAttribute 目前僅支援 .NET Framework。 如果您在 .NET Core、.NET 5+、UWP 或 WinUI 單元測試專案中嘗試使用此方法存取測試數據,您會看到類似 “'TestContext' 未包含 'DataRow' 的定義,找不到接受 'TestContext' 類型第一個參數的擴充方法 'DataRow' (是不是少了 using 指令或組件參考?)”。
建立數據源
若要測試 AddIntegers
方法,請建立數據源,指定參數的值範圍,以及您預期傳回的總和。 在此範例中,我們將建立名為 MathsData
的 Sql Compact 資料庫,以及名為 AddIntegersData
的數據表,其中包含下列數據行名稱和值
FirstNumber | SecondNumber | 總和 |
---|---|---|
0 | 1 | 1 |
1 | 1 | 2 |
2 | -3 | -1 |
將 TestContext 新增至測試類別
單元測試架構會建立 TestContext
物件,以儲存數據驅動測試的數據源資訊。 架構接著會將這個物件設定為您建立的 TestContext
屬性值。
public TestContext TestContext { get; set; }
在測試方法中,您可以透過 DataRow
的 TestContext
索引器屬性來存取數據。
撰寫測試方法
AddIntegers
的測試方法相當簡單。 針對數據源中的每一行,使用 AddIntegers
和 SecondNumber 欄值作為參數來呼叫 ,然後將傳回值與 Sum 欄值進行驗證。
[TestMethod]
[DataSource(@"Provider=Microsoft.SqlServerCe.Client.4.0; Data Source=C:\Data\MathsData.sdf;", "Numbers")]
public void AddIntegers_FromDataSourceTest()
{
var target = new Maths();
// Access the data
int x = Convert.ToInt32(TestContext.DataRow["FirstNumber"]);
int y = Convert.ToInt32(TestContext.DataRow["SecondNumber"]);
int expected = Convert.ToInt32(TestContext.DataRow["Sum"]);
int actual = target.AddIntegers(x, y);
Assert.AreEqual(expected, actual,
"x:<{0}> y:<{1}>",
new object[] {x, y});
}
指定 DataSourceAttribute
DataSource
屬性會指定數據源的連接字串,以及您在測試方法中使用的數據表名稱。 連接字串中的確切信息會根據您使用的數據源類型而有所不同。 在此範例中,我們使用 SqlServerCe 資料庫。
[DataSource(@"Provider=Microsoft.SqlServerCe.Client.4.0;Data Source=C:\Data\MathsData.sdf", "AddIntegersData")]
謹慎
連接字串可以包含敏感數據(例如密碼)。 連接字串以純文字形式儲存在原始碼和已編譯的程式集中。 限制對原始程式碼和元件的存取,以保護此敏感性資訊。
DataSource 屬性有三個建構函式。
[DataSource(dataSourceSettingName)]
具有一個參數的建構函式會使用儲存在解決方案 app.config 檔案中的連接資訊。 dataSourceSettingsName 是配置檔中指定連接資訊的 Xml 元素名稱。
使用 app.config 檔案可讓您變更數據源的位置,而不需變更單元測試本身。 如需如何建立和使用 app.config 檔案的詳細資訊,請參閱 逐步解說:使用組態檔定義數據源
[DataSource(connectionString, tableName)]
具有兩個參數的 DataSource
建構函式會指定數據源的連接字串,以及包含測試方法數據的數據表名稱。
連接字串取決於數據來源類型的類型,但它應該包含 Provider 元素,指定數據提供者的不變異名稱。
[DataSource(
dataProvider,
connectionString,
tableName,
dataAccessMethod
)]
使用 TestContext.DataRow 存取數據
若要存取 AddIntegersData
數據表中的數據,請使用 TestContext.DataRow
索引器。
DataRow
是 DataRow 物件,因此請依索引或數據行名稱擷取數據行值。 因為值會以 物件的形式傳回,因此將它們轉換成適當的類型:
int x = Convert.ToInt32(TestContext.DataRow["FirstNumber"]);
執行測試和檢視結果
當您完成撰寫測試方法之後,請建置測試專案。 測試方法會出現在 [未執行測試] 群組 的 [測試總管] 。 當您執行、寫入及重新執行測試時,[測試總管] 會顯示結果群組 失敗的測試、通過的測試,以及 [未執行測試]。 您可以選擇 [執行所有] 來執行所有測試,或選擇 [執行] 以選擇執行的測試子集。
測試管理器頂端的 測試結果列 在測試執行時會動畫顯示。 在測試回合結束時,如果所有測試都通過,則列會是綠色的,如果有任何測試失敗,則為紅色。 測試回合的摘要會出現在 [測試總管] 視窗底部的詳細數據窗格中。 選取測試以檢視底部窗格中該測試的詳細數據。
注意
每個數據列都有結果,還有一個摘要結果。 如果每個資料列的測試都通過,摘要結果會顯示為 通過。 如果測試在任何資料列上失敗,摘要執行會顯示為 [失敗] 。
如果您在範例中執行任何 AddIntegers_FromDataRowTest
、AddIntegers_FromDynamicDataTest
或 AddIntegers_FromDataSourceTest
方法,結果列會變成紅色,並將測試方法移至 失敗的測試。 如果數據源的任何反覆執行方法失敗,數據驅動測試就會失敗。 當您在 [測試總管] 視窗中選擇失敗的數據驅動測試時,詳細數據窗格會顯示數據列索引所識別的每個反復項目結果。 在我們的範例中,AddIntegers
演算法似乎未正確處理負值。
當測試中的方法修正並重新執行測試時,結果列會變成綠色,並將測試方法移至 [通過的測試] 群組。