Compartilhar via


Fonte de dados WMI

Verifique se você está familiarizado com a execução básica do TAEF e saiba como criar testes usando-o antes de prosseguir com esta seção.

Fundo

"WMI" significa "Instrumentação de Gerenciamento do Windows". Usando o CIM (Common Information Model), que é o padrão do setor para representar sistemas. A Instrumentação de Gerenciamento do Windows fornece uma maneira unificada de acessar informações de gerenciamento do sistema.

Como isso ajuda meus testes?

Usando o suporte à consulta WMI disponível como o WMI DataSource no TAEF, você pode adicionar uma pré-condição ao teste, bem como obter informações sobre os recursos no computador de teste antes de executar o teste. Aqui estão alguns dos exemplos do tipo de consulta que você pode fazer usando o WMI:

  • Verifique se o computador em que o teste está sendo executado é um laptop e execute o teste somente se for um laptop.
  • Verifique se um service pack foi instalado no computador de teste e execute o teste somente se ele tiver sido.
  • Recupere todas as unidades removíveis e unidades de disco rígido locais no computador de teste e execute o teste para cada uma das unidades que correspondem à consulta.
  • Execute o teste somente se o computador de teste não estiver ingressado no domínio OU
  • Execute o teste somente se o computador de teste estiver ingressado no domínio e recuperar o nome de domínio.

Isso teria lhe dado alguma ideia sobre onde e como você pode aproveitar o WMI DataSource para seu teste. Vamos examinar como adicionar esse suporte à consulta WMI durante a criação de um teste TAEF.

Os únicos metadados especiais necessários para fazer do teste um teste do WMI DataSource é o "DataSource". A sintaxe datasource deve ter a seguinte aparência:

[DataSource("WMI:<WQL query>")]

Ou no código nativo:

TEST_METHOD_PROPERTY(L"DataSource", L"WMI:<WQL query>")]

Você deve ter notado que o valor datasource começa com "WMI:", que permite que o TAEF saiba que essa é, de fato, a fonte de dados para um teste que depende do resultado da consulta WMI e também o distingue do teste controlado por dados. Essa é uma boa oportunidade para menção que atualmente o TAEF não dá suporte a um teste para ser ambos - um teste controlado por dados, bem como um teste que depende do resultado da consulta WMI.

A próxima pergunta naturalmente é como escrever consultas WQL para o que você está procurando? A sintaxe de consulta WQL é muito semelhante a consultas SQL simplificadas. Há alguns exemplos muito bons de consultas fornecidas em Tarefas WMI para Scripts e Aplicativos. Veja alguns exemplos:

SELECT Description, DesktopInteract, ProcessId FROM Win32_Service WHERE Name='Themes'
Execute o teste no serviço "Temas" depois de descobrir suas propriedades Description, DesktopInteract e ProcessId que você pretende usar em seu teste.

RECURSOS SELECT, CapabilityDescriptions FROM Win32_Printe
Execute o teste para cada impressora conectada a este computador. Permita que o teste acesse os Recursos e CapabilityDescriptions para cada impressora.

SELECT Name, User, Location FROM Win32_StartupCommand
Execute o teste para cada processo que é executado na inicialização do Windows. Para cada processo, permita que o teste saiba qual é o Nome do processo, onde ele está localizado (Local) e como Usuário o processo é executado.

Você pode encontrar mais exemplos na documentação mencionada acima, bem como no arquivo .cs e no arquivo de cabeçalho nos exemplos que você abriu. A sintaxe geral simplificada é a seguinte:

SELECT <comma separated properties> FROM <WMI Class name> [WHERE <add condition on some properties>]

Nos exemplos que você acabou de ver, Win32_Service, Win32_Printer e Win32_StartupCommand são todas classes WMI. Você pode pesquisar as classes WMI em classes WMI.

O TAEF não dá suporte à recuperação de propriedades do sistema.

Por trás da cena, o TAEF executará a consulta para você e confirmará o resultado. Se pelo menos um objeto for retornado como resultado da consulta, o teste será executado para cada objeto retornado. Se a consulta WQL não retornar nenhum objeto, o teste será registrado como Bloqueado com essas informações e a execução passará para o próximo teste.

Verificar ou verificar sua consulta antes de criar o teste parece ser uma ótima ideia e é um processo muito simples:

  • Na caixa de diálogo de execução ou em um prompt de comando, invoque "wbemtest.exe"
  • Clique no botão "Conectar" no canto superior direito.
  • Verifique se o namespace é "root\cimv2" antes de clicar em "Conectar" novamente no canto superior direito.
  • Em "IWbemServices", clique em "Consulta"
  • Insira sua consulta na caixa de edição exibida e clique em "Aplicar"

OBSERVAÇÃO: o "IWbemService" tem várias outras opções que podem ajudá-lo com sua consulta. Por exemplo, usar "Classes de Enumeração" e alterar o botão de opção para "recursivo" ajudará você a ver todas as classes WMI no sistema.

Recuperando propriedades consultadas usando a consulta WMI

Agora você tem uma ideia de como criar uma consulta WMI para um método de teste e como aplicá-la como metadados durante a criação de um teste. Você também sabe como confirmar se a consulta é válida usando wbemtest.exe. Agora vamos examinar como recuperar os valores de propriedade que você estava procurando.

As noções básicas sobre como recuperar essas informações são muito semelhantes à recuperação de valores para o teste controlado por dados. Por exemplo, no código gerenciado, isso teria a seguinte aparência:

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}

As linhas 24-30 no exemplo acima são exatamente o que é necessário para um teste controlado por dados gerenciado. Você definiu uma propriedade Privada TestContext e forneceu getter público e setter nela para TAEF definir os valores corretos. Usando a propriedade TestContext privada, você pode recuperar o valor atual de qualquer uma das propriedades do objeto resultante da consulta WMI que você recuperou do TAEF.

O código nativo para recuperar as propriedades WMI é muito semelhante. Assim como acontece com testes nativos controlados por dados, você usará TestData para obter os valores da propriedade. Por exemplo, vamos considerar o teste para obter propriedades da impressora padrão. O arquivo de cabeçalho cria esse teste da seguinte maneira:

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()

Para isso, nosso código de recuperação, no arquivo cpp, tem a seguinte aparência:

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    }

Contabilizando possíveis valores de propriedade NULL

A parte a ter em mente é que a consulta WMI nem sempre pode retornar uma propriedade não nula. Pode haver momentos em que o valor da propriedade WMI retornado é "nulo". Se você acha que a propriedade que você está procurando pode ser "nula" em alguns cenários, marcar para ela antes de verificar ou tentar usá-la.

No código de teste gerenciado, por exemplo, TestContext armazenará os valores nulos como um objeto do tipo DBNull. Você deve marcar se o objeto for do tipo DBNull antes de tentar converter o valor resultante para o tipo que você espera que seja. Vamos dar uma olhada:

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}

Por exemplo, no teste acima, "Compactado", "MaximumComponentLength" e "Availability" podem ser nulos em alguns cenários (quando a consulta retorna unidades removíveis como unidades de disquete). Você deseja garantir que o teste se comporte adequadamente nesses casos. Nesse sentido, recupere o valor da propriedade como um objeto e marcar se ele for do tipo "DBNull". Se for, significa que o valor da propriedade retornado era nulo. Se não for, o valor retornado não era nulo e, portanto, válido, portanto, converta-o para os tipos apropriados e use-o para o teste.

O mesmo acontece com as APIs de recuperação nativas também – o valor da propriedade retornado pode ser NULL. Isso significa que você precisa marcar se o TestData recuperou com êxito o valor sem usar uma chamada de verificação (já que não é possível recuperar pode ser porque o valor é nulo). Por exemplo, você pode ter um método de teste que depende de uma consulta 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()

Você pode ter "Availability e "MaximumComponentLength" retornados como valores NULL. Portanto, escreva o teste para considerar isso da seguinte forma:

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    }