Источник данных WMI
Прежде чем переходить к этому разделу, убедитесь, что вы знакомы с базовым выполнением TAEF и знаете, как создавать тесты с его помощью.
Фон
"WMI" означает "Инструментарий управления Windows". Использование общей информационной модели (CIM), которая является отраслевым стандартом для представления систем. Инструментарий управления Windows предоставляет единый способ доступа к сведениям об управлении системой.
Как это помогает моим тестам?
Используя поддержку запросов WMI, доступную в качестве источника данных WMI в TAEF, можно добавить в тест предусловие, а также получить сведения о ресурсах на тестовом компьютере перед запуском теста. Ниже приведены некоторые примеры типов запросов, которые можно выполнить с помощью инструментария WMI:
- Проверьте, является ли компьютер, на котором выполняется тест, ноутбуком, и запустите тест только в том случае, если это ноутбук.
- Проверьте, установлен ли пакет обновления на тестовом компьютере, и запустите тест только в том случае, если он был установлен.
- Получите все съемные и локальные жесткие диски на тестовом компьютере и выполните тест для каждого из дисков, соответствующих запросу.
- Запуск теста только в том случае, если тестовый компьютер не присоединен к домену ИЛИ
- Запустите тест, только если тестовый компьютер присоединен к домену, и получите доменное имя.
Мы надеемся, что это даст вам представление о том, где и как можно использовать WMI DataSource для тестирования. Давайте посмотрим, как добавить поддержку запросов WMI при создании теста TAEF.
Единственные специальные метаданные, необходимые для того, чтобы сделать тест 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 Capabilities, CapabilityDescriptions FROM Win32_Printe
Запустите тест для каждого принтера, подключенного к этому компьютеру. Разрешите тесту доступ к описаниям возможностей и возможностей для каждого принтера.
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. Теперь давайте рассмотрим, как получить значения свойств, которые вы искали.
Основы получения этих сведений очень похожи на получение значений для теста на основе данных. Например, в управляемом коде это будет выглядеть следующим образом:
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 и предоставили открытый метод получения и задания для TAEF, чтобы задать правильные значения. С помощью частного свойства TestContext можно получить текущее значение для любого свойства результирующих объектов WMI, полученных из TAEF.
Машинный код для получения свойств 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. Если это не так, возвращаемое значение не было пустым и, следовательно, допустимым. Поэтому приведите его к соответствующим типам и используйте его для тестирования.
То же самое относится и к собственным 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 }