共用方式為


WMI 資料來源

請確定您熟悉 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    }