Suporte a Dispositivos
Se a automação de teste depender da presença de dispositivos ou recursos de teste, consulte o exemplo TestResourceExample para entender como usar o suporte a dispositivos ou o suporte a recursos de teste disponíveis no TAEF. Antes de continuar, familiarize-se com a criação de testes básicos usando o TAEF e com a execução básica do TAEF.
Criação para suporte a dispositivos - Arquivo de códigos-fonte
O Te.Common.lib é necessário, além de outras bibliotecas necessárias para criar um teste no TAEF.
Criação para suporte a dispositivos – Definição de recurso de teste
Os usuários são responsáveis por criar suas definições de Recurso de teste (dispositivo). Para isso, você precisa implementar ITestResource. ITestResource é definido no arquivo de cabeçalho publicado ITestResource.h e tem a seguinte aparência:
namespace WEX { namespace TestExecution
{
namespace TestResourceProperty
{
// the following are reserved and must have properties for any TestResource definition
static const wchar_t c_szName[] = L"Name";
static const wchar_t c_szId[] = L"Id";
static const wchar_t c_szGuid[] = L"GUID";
static const wchar_t c_szType[] = L"Type";
}
struct __declspec(novtable) __declspec(uuid("79098e4c-b78d-434b-854d-2b59f5c4acc5")) ITestResource : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE GetGuid(GUID* pGuid) = 0;
virtual HRESULT STDMETHODCALLTYPE SetGuid(GUID guid) = 0;
virtual HRESULT STDMETHODCALLTYPE GetValue(BSTR name, BSTR* pValue) = 0;
virtual HRESULT STDMETHODCALLTYPE SetValue(BSTR name, BSTR value) = 0;
};
} /*namespace TestExecution*/ } /*namespace WEX*/
Em nosso exemplo, a classe MyTestResource implementa a interface COM ITestResource. Em ITestResource.h, você também encontrará uma lista de propriedades "obrigatórias" definidas. Deve ser possível obter o GUID para o recurso de teste usando GetGuid(..) e Nome, ID e Tipo do recurso usando GetValue(...). Se algum desses itens estiver ausente em um TestResource, o TAEF o considerará inválido e não manterá suas informações. (Consulte a seção "Criar a lista de recursos" a seguir).
Criação para suporte a dispositivos - Especificação de metadados dependentes de recursos
Para especificar que o módulo de teste tem métodos de teste dependentes de recursos de teste, uma propriedade de metadados de nível de módulo 'TestResourceDependent" deve ser definida como "true". A propriedade é herdada por todas as classes no módulo de teste e por todos os métodos de teste nessas classes. Se qualquer um dos métodos de teste no módulo não for dependente do recurso de teste, ele deverá redefinir explicitamente o valor de metadados como false. Todos os outros métodos de teste que dependem do recurso de teste devem fornecer uma consulta de seleção usando "Id" e/ou "Type" do recurso de teste.
Aqui estão alguns exemplos rápidos de "ResourceSelection" para a nossa lista de recursos de exemplo e o que cada um deles implica:
- "@Id='HD*'": associa cada recurso a uma ID começando com "HD"
- "@Type='PCI'": associa cada recurso do tipo "PCI"
- "@Id='PCI*' OU @Id='HD*'": associa cada recurso começando com "PCI" ou com "HD"
- "@Type='PCI' e @id='*37'": associa cada recurso do tipo "PCI" a um nome que termina em "37"
O nosso código de exemplo aparece assim:
BEGIN_MODULE()
MODULE_PROPERTY(L"TestResourceDependent", L"true")
END_MODULE()
class TestResourceExample
{
TEST_CLASS(TestResourceExample);
BEGIN_TEST_METHOD(NoTestResourceTest)
TEST_METHOD_PROPERTY(L"TestResourceDependent", L"false")
END_TEST_METHOD()
BEGIN_TEST_METHOD(OneHDAudioTest)
TEST_METHOD_PROPERTY(L"ResourceSelection", L"@Id='HD*'")
END_TEST_METHOD()
...
BEGIN_TEST_METHOD(HDorPCITest)
TEST_METHOD_PROPERTY(L"ResourceSelection", L"@Id='PCI*' OR @Id='HD*'")
END_TEST_METHOD()
...
};
No exemplo acima, você verá que o módulo está marcado como "TestResourceDependent". O NoTestResourceTest é explicitamente marcado como não dependente de nenhum recurso de teste, definindo metadados "TestRssourceDependent" como "false". Todos os outros métodos de teste especificam um critério de seleção para os recursos de teste em que há interesse de executar.
A gramática dos critérios de seleção é muito semelhante à gramática de consulta de seleção da linha de comando disponível para o TAEF. No entanto, no caso da seleção de recursos, ela é restrita ao uso de IDs e tipos de recursos. Como a ID do recurso é uma string, ela precisa ser colocada entre aspas simples. Você pode usar os caracteres curinga "*" ou "?" na especificação do valor da ID. No exemplo acima, em OneHDAudioTest, a seleção de recursos especifica uma correspondência para qualquer recurso em que ID comece com 'HD'. Da mesma forma, no caso de HDorPCITest, a seleção de recursos corresponderá a qualquer recurso em que a ID comece com 'HD' ou com 'PCI'. É importante observar que a seleção de recursos não diferencia maiúsculas de minúsculas. Ou seja, 'pci', 'Pci' e 'PCI' serão tratados da mesma forma.
Com base na seleção de recursos, o TAEF invocará novamente o método de teste juntamente com os métodos de configuração e limpeza no nível de teste (se especificados) uma vez para cada recurso de teste que corresponda à seleção. As seções a seguir exploram os detalhes sobre como especificar a lista de recursos e enviá-la ao TAEF e como o método de teste pode recuperar os recursos na próxima seção.
Criação para suporte a dispositivos - Criar a lista de recursos
Assim que o TAEF encontra um módulo de teste TestResourceDependent, ele procura e invoca o método exportado por dll BuildResourceList. É na implementação de BuildResourceList que os usuários podem criar novos recursos de teste e adicioná-los à interface que é passada como um parâmetro para BuildResourceList. Vamos dar uma olhada na implementação desse método em nosso exemplo:
using namespace WEX::TestExecution;
HRESULT __cdecl BuildResourceList(ResourceList& resourceList)
{
Log::Comment(L"In BuildResourceList");
GUID myGuid;
VERIFY_SUCCEEDED(::CoCreateGuid(&myGuid));
CComPtr<ITestResource> spTestResource;
spTestResource.Attach(new MyTestResource(L"HDAudio1", L"HDAudio-deviceid-1", myGuid, L"HD"));
resourceList.Add(spTestResource);
spTestResource.Attach(new MyTestResource(L"HDAudio2", L"HDAudio-deviceid-2", myGuid, L"HD"));
resourceList.Add(spTestResource);
spTestResource.Attach(new MyTestResource(L"PCI1", L"PCI-deviceid-1", myGuid, L"PCI"));
resourceList.Add(spTestResource);
spTestResource.Attach(new MyTestResource(L"PCI2", L"PCI-deviceid-2", myGuid, L"PCI"));
resourceList.Add(spTestResource);
spTestResource.Attach(new MyTestResource(L"PCI3", L"PCI-deviceid-3", myGuid, L"PCI"));
resourceList.Add(spTestResource);
return S_OK;
}
BuildResourceList aceita uma referência a WEX::TestExecution::ResourceList como seu parâmetro. ResourceList é definido no arquivo de cabeçalho publicado ResourceList.h. Usando o método Add(...) em ResourceList, os usuários podem adicionar todos os recursos de teste descobertos ou criados para o TAEF gerenciar e usar. O exemplo acima adicionou 5 desses recursos de teste.
O método Add falhará se o recurso de teste a ser adicionado não retornar "Name", "Id", "Type" ou GUID para o recurso.
O ResourceList será mantido pela duração do módulo de teste, ou seja, até que todos os métodos de teste e métodos de limpeza sejam concluídos. Se BuildResourceList retornar um valor FAILED HRESULT, todos os métodos de teste dependentes de recursos no módulo de teste serão registrados como bloqueados sem execução. Todos os recursos que não são de teste serão executados independentemente.
BuildResourceList é invocado antes de qualquer outro método no módulo de teste. Depois que a lista de recursos é criada (em BuildResourceList), os metadados "ResourceSelection" são usados para corresponder aos recursos disponíveis na lista de recursos. Se uma correspondência for encontrada, todos os métodos de configuração (módulo, classe, ordem de teste) serão invocados seguidos pelo próprio método de teste. O método de limpeza de nível de teste é chamado após cada invocação de teste.
Nos bastidores, o TAEF retém o ResourceList em que a seleção de recursos é aplicada. Por exemplo, para o método de teste OneHDAudioTest, os recursos de teste com as IDs "HDAudio-deviceid-1" e "HDAudio-deviceid-2" corresponderão a 'HD*' e, para cada um deles, o método de teste será invocado novamente pelo TAEF (uma vez para cada). Também haverá um índice implícito associado a cada invocação do teste. Portanto, você verá o <qualificador de namespace> OneHDAudioTest#0 e o <qualificador de namespace> OneHDAudioTest#1 como as duas invocações.
Criação para suporte a dispositivos – Recuperar o dispositivo em um método de teste
As seções anteriores exploraram como adicionar os metadados necessários no nível do módulo, classe e método de teste. Também analisaram como definir recursos de teste personalizados e como adicioná-los ao ResourceList na implementação de BuildResourceList. A próxima parte é recuperar os recursos no método de teste. Vamos dar uma olhada em um dos métodos de teste simples em nosso exemplo:
1 void TestResourceExample::OneHDAudioTest()
2 {
3 Log::Comment(L"In HD audio test");
4 size_t count = Resources::Count();
5 size_t index = 0;
6 VERIFY_ARE_EQUAL(count, (index + 1));
7
8 CComPtr<ITestResource> spTestResource;
9 VERIFY_SUCCEEDED(Resources::Item(index, &spTestResource));
10
11 // Get Resource Id
12 CComBSTR value;
13 VERIFY_SUCCEEDED(spTestResource->GetValue(CComBSTR(TestResourceProperty::c_szId), &value));
14 Log::Comment(L"Resource Id is " + String(value));
15 }
Em OneHDAudioTest, a seleção de recursos usa um recurso de teste por vez em que a ID do recurso começa com 'HD'. A classe estática Resources definida em ResourceList.h fornece as APIs para recuperar a contagem, bem como o recurso real disponível durante qualquer invocação do teste. Nesse caso, como você pode ver nas linhas 4, 9 e 13 no exemplo acima, Resources::Count() fornece a contagem do número de recursos de teste disponíveis durante a invocação atual do método de teste. Neste método de teste, deve ser 1. Você pode verificar esse valor usando as macros VERIFY disponíveis em TAEF (Verify.h). Como você sabe, se qualquer uma das chamadas de verificação falhar em um teste TAEF baseado em exceção, a execução será encerrada nesse ponto e o método de teste será marcado como Failed.
Em seguida, ao usar a API Resources::Item(...) e passar um índice no qual recuperar o recurso (nesse caso, como apenas um recurso de teste estará disponível durante uma invocação, o índice sempre será 0), você pode recuperar o recurso de teste. O método de teste pode usar ainda mais o recurso de teste recuperado conforme necessário para seu teste.
O mesmo princípio básico é seguido em todos os métodos de teste. Confira outros métodos de teste no exemplo para entender melhor.
Executar um módulo de teste dependente de recursos de teste
Com os testes dependentes de recursos de teste criados e compilados, agora você pode executá-los usando o TAEF. O ponto principal a ser observado é que os testes TestResourceDependent só podem ser executados inproc. Isso significa que, mesmo que você não especifique explicitamente a opção "/inproc", ela será adicionada assim que o TAEF descobrir o módulo de teste dependente do recurso de teste. Como você deve saber, os testes de apenas um módulo podem passar por determinada execução do TAEF quando a opção "/inproc" está presente. Isso significa que você não pode especificar mais de um módulo de teste na linha de comando se o módulo de teste for dependente do recurso.
Para realmente executar todos os testes em nosso módulo de teste, você pode simplesmente executar:
te Examples\Cpp.TestResource.Example.dll
Uma maneira útil de obter uma lista de todas as invocações de método de teste e as combinações de dados e metadados sem realmente executar os métodos de teste é usar a opção /listproperties na linha de comando. Vamos conferir o resultado.
te Examples\Cpp.TestResource.Example.dll /listproperties
Test Authoring and Execution Framework v2.9.3k for x86
In BuildResourceList
Verify: SUCCEEDED(::CoCreateGuid(&myGuid))
f:\toolsdev.binaries.x86chk\WexTest\CuE\TestExecution\Examples\Cpp.TestResource.Example.dll
Property[TestResourceDependent] = true
WEX::TestExecution::Examples::TestResourceExample
WEX::TestExecution::Examples::TestResourceExample::NoTestResourceTest
Property[TestResourceDependent] = false
WEX::TestExecution::Examples::TestResourceExample::OneHDAudioTest#0
Property[ResourceSelection] = @Id='HD*'
Resource#0
Id = HDAudio-deviceid-1
Name = HDAudio1
Type = HD
WEX::TestExecution::Examples::TestResourceExample::OneHDAudioTest#1
Property[ResourceSelection] = @Id='HD*'
Resource#0
Id = HDAudio-deviceid-2
Name = HDAudio2
Type = HD
WEX::TestExecution::Examples::TestResourceExample::OnePCIDeviceTest#0
Property[ResourceSelection] = @Id='PCI*'
Resource#0
Id = PCI-deviceid-1
Name = PCI1
Type = PCI
WEX::TestExecution::Examples::TestResourceExample::OnePCIDeviceTest#1
Property[ResourceSelection] = @Id='PCI*'
Resource#0
Id = PCI-deviceid-2
Name = PCI2
Type = PCI
WEX::TestExecution::Examples::TestResourceExample::OnePCIDeviceTest#2
Property[ResourceSelection] = @Id='PCI*'
Resource#0
Id = PCI-deviceid-3
Name = PCI3
Type = PCI
WEX::TestExecution::Examples::TestResourceExample::HDorPCITest#0
Property[ResourceSelection] = @Id='PCI*' OR @Id='HD*'
Resource#0
Id = HDAudio-deviceid-1
Name = HDAudio1
Type = HD
WEX::TestExecution::Examples::TestResourceExample::HDorPCITest#1
Property[ResourceSelection] = @Id='PCI*' OR @Id='HD*'
Resource#0
Id = HDAudio-deviceid-2
Name = HDAudio2
Type = HD
WEX::TestExecution::Examples::TestResourceExample::HDorPCITest#2
Property[ResourceSelection] = @Id='PCI*' OR @Id='HD*'
Resource#0
Id = PCI-deviceid-1
Name = PCI1
Type = PCI
WEX::TestExecution::Examples::TestResourceExample::HDorPCITest#3
Property[ResourceSelection] = @Id='PCI*' OR @Id='HD*'
Resource#0
Id = PCI-deviceid-2
Name = PCI2
Type = PCI
WEX::TestExecution::Examples::TestResourceExample::HDorPCITest#4
Property[ResourceSelection] = @Id='PCI*' OR @Id='HD*'
Resource#0
Id = PCI-deviceid-3
Name = PCI3
Type = PCI
WEX::TestExecution::Examples::TestResourceExample::PCI1AudioTest #0
Property[ResourceSelection] = @Id='PCI*' AND @Id='*1'
Resource#0
Id = PCI-deviceid-1
Name = PCI1
Type = PCI
Observe o índice implícito que é adicionado ao nome do método de teste durante cada invocação de um método de teste dependente do recurso de teste. A propriedade ResourceSelection é mostrada seguida por uma lista de todos os recursos que estarão disponíveis para o método de teste na ordem em que estarão disponíveis. Por exemplo, no caso da terceira invocação de HDAudioHDAudioPCITest (HDAudioHDAudioPCITest#2), HDAudio-deviceid-1 será o recurso disponível no índice 0 em Resources::Item(...).
Você pode especificar melhor qual invocação de teste deseja usando a linguagem de consulta de seleção de linha de comando disponível no TAEF. Por exemplo, para selecionar todas as invocações de métodos de teste em que os recursos de teste 'PCI-deviceid-3' estão disponíveis, você pode usar os critérios de seleção:
te Examples\Cpp.TestResource.Example.dll /list
/select:"@Resource:Id='PCI-deviceid-3'"
Test Authoring and Execution Framework v2.9.3k for x86
In BuildResourceList
Verify: SUCCEEDED(::CoCreateGuid(&myGuid))
f: \Examples\Cpp.TestResource.Example.dll
WEX::TestExecution::Examples::TestResourceExample
WEX::TestExecution::Examples::TestResourceExample::OnePCIDeviceTest#2
WEX::TestExecution::Examples::TestResourceExample::HDorPCITest#4
Da mesma forma, para selecionar um método de teste específico por nome (considerando que os nomes dos métodos de teste são totalmente qualificados junto com o índice de invocação acrescentado no final), você pode usar uma consulta de seleção da seguinte maneira:
te Examples\Cpp.TestResource.Example.dll /name:*OneHDAudioTest#1
Test Authoring and Execution Framework v2.2 Build 6.1.7689.0 (release.091218-1251) for x86
Discovered a test resource dependent test module. Assuming /InProc execution.
In BuildResourceList
Verify: SUCCEEDED(::CoCreateGuid(&myGuid))
StartGroup: WEX::TestExecution::Examples::TestResourceExample::OneHDAudioTest#1
In HD audio test
Verify: AreEqual(count, (index + 1))
Verify: SUCCEEDED(Resources::Item(index, &spTestResource))
Verify: SUCCEEDED(spTestResource->GetValue(CComBSTR(TestResourceProperty::c_szId), &value))
Resource Id is HDAudio-deviceid-2
WEX::TestExecution::Examples::TestResourceExample::OneHDAudioTest#1 [Passed]
Summary: Total=1, Passed=1, Failed=0, Blocked=0, Not Run=0, Skipped=0
Observe o aviso implícito adicionado a inproc na terceira linha do exemplo acima. A consulta de seleção acima teve o mesmo efeito que a consulta de seleção:/select:"@Name='*OneHDAudio*' And @Resource:Index=1". Também é possível selecionar um recurso usando seu Nome ou Tipo (ou ID, conforme mostrado acima). Por exemplo, /select:"@Name='*PCIHDAudioTest*' e @Resource:Name='PCI3'" selecionarão os métodos de teste PCIHDAudioTest#4 e PCIHDAudioTest#5.
Testar essas e outras consultas de seleção no prompt de comando é deixado como um exercício para o leitor.