Partilhar via


Fonte de dados WMI

Por favor, certifique-se de que você está familiarizado com a execução básica do TAEF e sabe como criar testes usando-o, antes de prosseguir com esta seção.

Contexto geral

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

Como é que ajuda os meus testes?

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

  • Verifique se a máquina 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 na máquina de teste e execute o teste somente se tiver sido.
  • Recupere todas as unidades removíveis e unidades de disco rígido locais na máquina de teste e execute o teste para cada uma das unidades que correspondem à consulta.
  • Execute o teste somente se a máquina de teste não estiver associada ao domínio OU
  • Execute o teste somente se a máquina de teste estiver associada ao domínio e recuperar o nome de domínio.

Espera-se que isso tenha lhe dado alguma ideia sobre onde e como você pode aproveitar a fonte de dados WMI para seus testes. Vamos ver como adicionar esse suporte à consulta WMI durante a criação de um teste TAEF.

Os únicos metadados especiais que você precisa para tornar seu teste um teste WMI DataSource é o "DataSource". A sintaxe DataSource deve ter a seguinte aparência:

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

Ou em código nativo:

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

Você deve ter notado que o valor DataSource começa com "WMI:", o que permite que o TAEF saiba que essa é realmente a fonte de dados para um teste que depende do resultado da consulta WMI e também o distingue do teste controlado por dados. Esta é uma boa oportunidade para mencionar que, atualmente, o TAEF não suporta que um teste seja ao mesmo tempo orientado por dados e dependa do resultado da consulta WMI.

A próxima pergunta naturalmente é como escrever consultas WQL para o que você está procurando? A sintaxe da consulta WQL é muito semelhante às consultas SQL simplificadas. Existem alguns exemplos muito bons de consultas fornecidas em Tarefas WMI para scripts e aplicativos. Eis alguns exemplos:

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

SELECT Capacidades, CapacidadeDescrições DE Win32_Printe
Execute o teste para cada impressora conectada a este computador. Permita que o teste aceda às Capacidades e Descrições de Capacidades de cada impressora.

SELECT Nome, Utilizador, Localização de Win32_StartupCommand
Execute o teste para cada processo que é executado na inicialização do Windows. Para cada processo, deixe o teste saber 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 e excessivamente 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 procurar as classes WMI em classes WMI.

O TAEF não suporta a recuperação de Propriedades do Sistema.

Nos bastidores, 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 seu teste parece ser uma ótima ideia, e é um processo muito simples:

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

NOTA: O "IWbemService" tem várias outras opções que podem ajudá-lo com a sua consulta. Por exemplo, utilizar "Enum Classes" e alterar o botão rádio para "recursivo" irá ajudá-lo a ver todas as classes WMI no sistema.

Recuperando propriedades consultadas usando a consulta WMI

Agora você já tem uma idéia de como criar uma consulta WMI para um método de teste e como aplicá-lo 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 ver 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 seu teste orientado por dados. Por exemplo, no código gerenciado, isso seria parecido com o seguinte:

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 gerenciados. Você definiu uma propriedade TestContext privada e forneceu getter e setter público nela para que o TAEF definisse os valores corretos. Usando a propriedade privada TestContext, você pode recuperar o valor atual para 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. Como nos testes controlados por dados nativos, você usará TestData para obter os valores de propriedade. Por exemplo, vamos considerar o teste para obter propriedades da impressora padrão. O arquivo de cabeçalho cria este teste assim:

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    }

Considerando possíveis valores de propriedade NULL

O que se deve ter em mente é que a consulta WMI nem sempre pode retornar uma propriedade não nula. Pode haver vezes em que o valor da propriedade WMI retornado é "nulo". Se achar que a propriedade que está a procurar pode ser nula em alguns cenários, então verifique antes de confirmá-la ou tentar utilizá-la.

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

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, "Compressed", "MaximumComponentLength" e "Availability" podem ser nulos em alguns cenários (quando a consulta retorna unidades removíveis, como unidades de disquete). Deve certificar-se de que o teste se comporta adequadamente nesses casos. Para esse fim, recupere o valor da propriedade como um objeto e verifique se ele é do tipo "DBNull". Se for, significa que o valor da propriedade retornado foi nulo. Se não for, o valor retornado não foi nulo e, por conseguinte, é válido - então converta-o para os tipos apropriados e use-o para o teste.

O mesmo é verdadeiro com APIs de recuperações nativas também - o valor da propriedade retornada pode ser NULL. Isso significa que você precisa verificar se o TestData recuperou com êxito o valor sem usar uma chamada de verificação (já que não ser capaz de 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. Então, escreva o teste para explicar isso assim:

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    }