WMI 資料來源
請先確定您已熟悉 TAEF 的基本執行,並知道如何使用它撰寫測試,再繼續進行本節。
背景
「WMI」 代表 「Windows Management Instrumentation」。 使用通用訊息模型 (CIM) ,這是代表系統的業界標準。 Windows Management Instrumentation 提供存取系統管理資訊的統一方式。
其如何協助我的測試?
您可以使用 WMI 查詢支援作為 TAEF 中的 WMI DataSource,在測試中新增前置條件,以及在執行測試之前取得測試機器上資源的相關資訊。 以下是您可以使用 WMI 進行之查詢類型的一些範例:
- 檢查測試執行所在的電腦是否為膝上型電腦,且只有在其為膝上型電腦時才執行測試。
- 檢查測試機器上是否已安裝 Service Pack,並只在已安裝時執行測試。
- 擷取測試電腦上的所有抽取式磁片磁碟機和本機硬碟,並針對符合查詢的每個磁片磁碟機執行測試。
- 只有在測試電腦未加入網域或時,才執行測試
- 只有在測試電腦已加入網域並擷取功能變數名稱時,才執行測試。
這可希望您瞭解 WMI DataSource 在何處及如何運用 WMI DataSource 進行測試。 讓我們看看如何在撰寫 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 Description, DesktopInteract, ProcessId FROM Win32_Service WHERE Name='Themes'
在找出您想要在測試中使用的 Description、DesktopInteract 和 ProcessId 屬性之後,在 「Themes」 服務上執行測試。
SELECT 功能、功能描述 FROM Win32_Printe
針對連線到這部電腦的每部印表機執行測試。 允許測試存取每部印表機的 Capabilities and CapabilityDescriptions。
SELECT Name, User, Location 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 行完全是 Managed 資料驅動測試所需的專案。 您已定義私人 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」。 如果您認為您正在尋找的屬性在某些情況下可能是「null」,請在驗證或嘗試使用它之前先檢查它。
例如,在 Managed 測試程式碼中,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」 可為 null。 您想要確定測試在這類情況下會適當運作。 在此結尾,將屬性值擷取為物件,並檢查其類型是否為 「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 and 」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 }