請確定您熟悉 TAEF 的基本執行,並知道如何使用它來撰寫測試,再繼續本節。
背景
“WMI”代表“Windows Management Instrumentation”。 使用通用資訊模型 (CIM),這是表示系統的業界標準。 Windows Management Instrumentation 提供存取系統管理資訊的統一方式。
它對我的測試有何幫助?
使用 TAEF 中 WMI 數據源可用的 WMI 查詢支援,您可以將前置條件新增至測試,並在執行測試之前取得測試計算機上資源的相關資訊。 以下是您可以使用 WMI 進行的查詢類型的一些範例:
- 檢查執行測試的電腦是否是筆記型電腦,並且只在是筆記型電腦時才執行測試。
- 檢查測試電腦上是否已安裝 Service Pack,並僅在已安裝時才執行測試。
- 擷取測試電腦上的所有抽取式磁碟機和本機硬碟,並針對符合查詢的每個磁碟機執行測試。
- 僅當測試機器未加入網域時執行測試,或
- 只有在測試機器已加入網域並擷取網域名稱時,才執行測試。
這有望讓您了解在何處以及如何利用 WMI 數據源進行測試。 讓我們看看如何在撰寫 TAEF 測試時新增此 WMI 查詢支援。
將測試設為 WMI DataSource 測試所需的唯一特殊中繼資料是 “DataSource”。 DataSource 語法必須如下所示:
[DataSource("WMI:<WQL query>")]
或在本機程式碼中:
TEST_METHOD_PROPERTY(L"DataSource", L"WMI:<WQL query>")]
您一定已經注意到 DataSource 值以 「WMI:」開頭,這讓 TAEF 知道這確實是相依於 WMI 查詢結果的測試的資料來源,而且也會將其與數據驅動測試區分開來。 這是很好的機會,可以提及目前 TAEF 不支援同時是 - 數據驅動測試,以及相依於 WMI 查詢結果的測試。
下一個問題自然是如何為您正在尋找的內容編寫 WQL 查詢? WQL 查詢語法與簡化的 SQL 查詢非常相似。 腳本和應用程式的 WMI 工作中提供了一些非常好的查詢範例。 以下是一些範例:
SELECT 描述、DesktopInteract、ProcessId FROM Win32_Service WHERE Name='Themes'
在找出您要在測試中使用的 Description、DesktopInteract 和 ProcessId 屬性之後,在「主題」服務上執行測試。
SELECT Capabilities, CapabilityDescriptions FROM Win32_Printe
針對連線到此電腦的每台印表機執行測試。 允許測試存取每部印表機的功能和功能描述。
SELECT 名稱、使用者、位置 FROM Win32_StartupCommand
針對 Windows 啟動時執行的每個進程執行測試。 對於每個進程,讓測試知道進程的名稱、它所在的位置(位置)以及進程以哪個使用者身分執行。
您可以在上述文件以及您開啟的範例中的.cs檔案和頭檔中找到更多範例。 一般、過度簡化的語法如下:
SELECT <comma separated properties> FROM <WMI Class name> [WHERE <add condition on some properties>]
在您剛才看到的範例中,Win32_Service、Win32_Printer和Win32_StartupCommand都是 WMI 類別。 您可以在 WMI 類別中查閱 WMI 類別。
TAEF 不支援擷取系統屬性。
在幕後,TAEF 會為您執行查詢並確認結果。 如果查詢的結果至少傳回一個物件,則會針對每個傳回的物件執行測試。 如果 WQL 查詢未傳回任何物件,則測試會記錄為 [已封鎖] 並繼續執行下一個測試。
在撰寫測試之前檢查或驗證查詢似乎是個好主意,而且是一個非常簡單的過程:
- 從執行對話框或命令提示符叫用“wbemtest.exe”
- 點擊右上角的「連接」按鈕。
- 確保您的命名空間是“root\cimv2”,然後再次單擊右上角的“連接”。
- 在「IWbemServices」下,按一下「查詢」
- 在出現的編輯框中輸入您的查詢,然後單擊“應用”
注意:「IWbemService」還有其他幾個選項可以幫助您進行查詢。 例如,使用「列舉類別」並將單選按鈕變更為「遞迴」,將協助您查看系統上的所有 WMI 類別。
擷取使用 WMI 查詢的屬性
到目前為止,您已經瞭解如何為測試方法提出 WMI 查詢,以及如何在撰寫測試時將其套用為中繼資料。 您也知道如何使用 wbemtest.exe確認查詢有效。 現在讓我們看看如何擷取您要尋找的屬性值。
擷取此資訊的基本原則與擷取資料驅動測試的值非常類似。 例如,在 Managed 程式碼中,這看起來如下:
1 namespace WEX.Examples
2 {
3 using Microsoft.VisualStudio.TestTools.UnitTesting;
4 using System;
5 using System.Collections;
6 using System.Data;
7 using WEX.Logging.Interop;
8 using WEX.TestExecution;
9
10 [TestClass]
11 public class CSharpWmiDataSourceExample
12 {
13 [TestMethod]
14 [DataSource("WMI:SELECT Description, DesktopInteract, ProcessId FROM Win32_Service WHERE Name='Themes'")]
15 public void ThemesTest()
16 {
17 String description = (String)m_testContext.DataRow["Description"];
18 Boolean desktopInteract = (Boolean)m_testContext.DataRow["DesktopInteract"];
19 UInt32 processId = (UInt32)m_testContext.DataRow["ProcessId"];
20 Log.Comment("Themes service is running on process " + processId.ToString() + " with desktop interact set to "
+ desktopInteract.ToString());
21 Log.Comment("Themes service description: " + description);
22 }
23 ...
24 public TestContext TestContext
25 {
26 get { return m_testContext; }
27 set { m_testContext = value; }
28 }
29
30 private TestContext m_testContext;
31 }
32}
上述範例中的第 24-30 行正是受管理資料驅動測試所需的內容。 您定義了私人 TestContext 屬性,並在其上提供公用 getter 和 setter,讓 TAEF 設定正確的值。 使用私人 TestContext 屬性,您可以擷取您從 TAEF 擷取之任何 WMI 查詢結果物件屬性的目前值。
擷取 WMI 屬性的原生程式碼非常類似。 如同原生數據驅動測試,您將使用 TestData 來取得屬性值。 例如,讓我們考慮獲取默認打印機屬性的測試。 標頭檔會撰寫此測試,如下所示:
1 // Test on the default printer and its driver name
2 BEGIN_TEST_METHOD(DefaultPrinterTest)
3 TEST_METHOD_PROPERTY(L"DataSource",
L"WMI:SELECT DriverName, DeviceId, LanguagesSupported FROM Win32_Printer WHERE Default = True")
4 END_TEST_METHOD()
為此,我們在 cpp 檔案中的檢索程式碼如下所示:
1 void WmiExample::DefaultPrinterTest()
2 {
3 String deviceId;
4 VERIFY_SUCCEEDED(TestData::TryGetValue(L"DeviceId", deviceId));
5
6 String driverName;
7 VERIFY_SUCCEEDED(TestData::TryGetValue(L"DriverName", driverName));
8
9 TestDataArray<unsigned int> languagesSupported;
10 VERIFY_SUCCEEDED(TestData::TryGetValue(L"LanguagesSupported", languagesSupported));
11
12 Log::Comment(L"The default driver is " + deviceId + L" which is a " + driverName);
13 size_t count = languagesSupported.GetSize();
14 for (size_t i = 0; i < count; i++)
15 {
16 Log::Comment(String().Format(L"Language supported: %d", languagesSupported[i]));
17 }
18 }
考慮可能的 NULL 屬性值
要記住的部分是,WMI 查詢可能不一定會傳回非 Null 屬性。 傳回的 WMI 屬性值可能會為 “Null”。 如果您認為要尋找的屬性在某些情況下可能是「空值」,請在驗證或嘗試使用它之前先檢查它。
例如,在受控測試程式碼中,TestContext 會將 Null 值儲存為 DBNull 類型的物件。 您必須先檢查物件是否屬於 DBNull 類型,才能嘗試將結果值轉換成您預期的類型。 讓我們看看:
1 namespace WEX.Examples
2 {
3 using Microsoft.VisualStudio.TestTools.UnitTesting;
4 using System;
5 using System.Collections;
6 using System.Data;
7 using WEX.Logging.Interop;
8 using WEX.TestExecution;
9
10 [TestClass]
11 public class CSharpWmiDataSourceExample
12 {
13 [TestMethod]
14 [DataSource("WMI:SELECT MaximumComponentLength, Availability, DeviceId, DriveType, Compressed
FROM Win32_LogicalDisk WHERE DriveType=2 Or DriveType=3")]
15 public void LogicalDiskTest()
16 {
17 UInt32 driveType = (UInt32)m_testContext.DataRow["DriveType"];
18 Log.Comment("DeviceId is " + m_testContext.DataRow["DeviceId"]);
19 Log.Comment("DriveType is " + driveType.ToString());
20
21 object nullCheckCompressed = m_testContext.DataRow["Compressed"];
22 Log.Comment("Compressed's type is: " + nullCheckCompressed.GetType().ToString());
23 if (nullCheckCompressed.GetType() == typeof(DBNull))
24 {
25 Log.Comment("Compressed is NULL");
26 }
27 else
28 {
29 Boolean compressed = (Boolean)nullCheckCompressed;
30 Log.Comment("Compressed is " + compressed.ToString());
31 }
32
33 object nullCheckMaxComponentLength = m_testContext.DataRow["MaximumComponentLength"];
34 if (nullCheckMaxComponentLength.GetType() == typeof(DBNull))
35 {
36 Log.Comment("MaxComponentLength is NULL");
37 }
38 else
39 {
40 UInt32 maxComponentLength = (UInt32)nullCheckMaxComponentLength;
41 Log.Comment("MaxComponentLength is " + maxComponentLength.ToString());
42 }
43
44 object nullCheckAvailability = m_testContext.DataRow["Availability"];
45 if (nullCheckAvailability.GetType() == typeof(DBNull))
46 {
47 Log.Comment("Availability is NULL");
48 }
49 else
50 {
51 UInt32 availability = (UInt32)nullCheckAvailability;
52 Log.Comment("Availability is " + availability.ToString());
53 }
54 }
55 ...
56 public TestContext TestContext
57 {
58 get { return m_testContext; }
59 set { m_testContext = value; }
60 }
61
62 private TestContext m_testContext;
63 }
64}
例如,在上述測試中,「Compressed」、「MaximumComponentLength」和「Availability」在某些情況下可能為空值(例如查詢回傳如軟碟機之類的卸除式磁碟機時)。 您想要確保測試在這種情況下表現得適當。 為此,將屬性值檢索為物件並檢查它是否屬於「DBNull」類型。 如果是,則表示傳回的屬性值為 Null。 如果不是,則傳回的值不是 Null,因此有效 - 因此請將其轉換成適當的類型,並將其用於測試。
原生擷取 API 也是如此 - 傳回的屬性值可能是 NULL。 這表示您必須檢查 TestData 是否成功擷取值,而不使用驗證呼叫 (因為無法擷取可能是因為值為 Null) 。 例如,您可能有一個相依於 WMI 查詢的測試方法:
1 // Test on only local (drive type = 3) or removable (drive type = 2) harddrive
2 BEGIN_TEST_METHOD(LocalOrRemovableHardDriveTest)
3 TEST_METHOD_PROPERTY(L"DataSource", L"WMI:SELECT DeviceId, DriveType, Availability,
MaximumComponentLength FROM Win32_LogicalDisk WHERE DriveType=2 OR DriveType=3")
4 END_TEST_METHOD()
您可能會將 “Availability 和 ”MaximumComponentLength“ 傳回為 NULL 值。 因此,請編寫測試來解釋這一點,如下所示:
1 void WmiExample::LocalOrRemovableHardDriveTest()
2 {
3 String deviceId;
4 VERIFY_SUCCEEDED(TestData::TryGetValue(L"DeviceId", deviceId));
5 int driveType;
6 VERIFY_SUCCEEDED(TestData::TryGetValue(L"DriveType", driveType));
7
8 unsigned int maxComponentLength;
9 if (SUCCEEDED(TestData::TryGetValue(L"MaximumComponentLength", maxComponentLength)))
10 {
11 Log::Comment(String().Format(L"MaximumComponentLength: %d", maxComponentLength));
12 }
13
14 unsigned int availability;
15 if (SUCCEEDED(TestData::TryGetValue(L"Availability", availability)))
16 {
17 Log::Comment(String().Format(L"Availability: %d", availability));
18 }
19
20 Log::Comment(L"DeviceId: " + deviceId);
21 Log::Comment(String().Format(L"DriveType: %d", driveType));
22 }