WMI 데이터 원본

이 섹션을 진행하기 전에 TAEF의 기본 실행에 익숙하고 이를 사용하여 테스트를 작성하는 방법을 알고 있는지 확인하세요.

배경

"WMI"는 "Windows Management Instrumentation"을 의미합니다. 시스템을 나타내는 업계 표준인 CIM(공용 정보 모델)을 사용합니다. Windows Management Instrumentation은 시스템 관리 정보에 액세스하는 통합된 방법을 제공합니다.

테스트에 어떤 도움이 됩니까?

TAEF에서 WMI DataSource로 사용할 수 있는 WMI 쿼리 지원을 사용하여 테스트를 실행하기 전에 테스트에 사전 조건을 추가하고 테스트 머신의 리소스에 대한 정보를 가져올 수 있습니다. 다음은 WMI를 사용하여 만들 수 있는 쿼리의 종류에 대한 몇 가지 예입니다.

  • 테스트가 실행 중인 컴퓨터가 랩톱인지 확인하고 랩톱인 경우에만 테스트를 실행합니다.
  • 테스트 컴퓨터에 서비스 팩이 설치되어 있는지 확인하고 테스트가 설치된 경우에만 테스트를 실행합니다.
  • 테스트 머신에서 모든 이동식 드라이브 및 로컬 하드 디스크 드라이브를 검색하고 쿼리와 일치하는 각 드라이브에 대해 테스트를 실행합니다.
  • 테스트 머신이 도메인에 가입되어 있지 않은 경우에만 테스트를 실행합니다.
  • 테스트 머신이 도메인에 가입된 경우에만 테스트를 실행하고 도메인 이름을 검색합니다.

테스트를 위해 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 속성을 찾은 후 "테마" 서비스에서 테스트를 실행합니다.

SELECT 기능, CapabilityDescriptions FROM Win32_Printe
이 컴퓨터에 연결된 각 프린터에 대해 테스트를 실행합니다. 테스트가 각 프린터의 기능 및 기능 설명에 액세스하도록 허용합니다.

SELECT 이름, 사용자, 위치 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 사용하여 쿼리가 유효한지 확인하는 방법도 알고 있습니다. 이제 찾고 있던 속성 값을 검색하는 방법을 살펴보겠습니다.

이 정보를 검색하는 기본 사항은 데이터 기반 테스트에 대한 값을 검색하는 것과 매우 유사합니다. 예를 들어 관리 코드에서는 다음과 같이 표시됩니다.

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줄은 관리되는 데이터 기반 테스트에 정확히 필요합니다. private TestContext 속성을 정의하고 TAEF가 올바른 값을 설정하도록 공용 getter 및 setter를 제공했습니다. private 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"일 수 있다고 생각되면 확인하거나 사용하기 전에 검사.

예를 들어 관리되는 테스트 코드에서 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()

"가용성 및 "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    }