设备支持
如果测试自动化依赖于设备或测试资源的存在,请参阅示例 TestResourceExample,并遵循如何利用 TAEF 中提供的设备支持或测试资源支持。 在继续操作之前,请确保熟悉如何使用 TAEF 编写基本测试以及 TAEF 的基本执行。
为设备支持创作 - 源文件
除了在 TAEF 中编写测试所需的其他库外,还需要 Te.Common.lib。
为设备支持创作 - 测试资源定义
用户负责创建自己的测试资源(设备)定义。 为此,需要实现 ITestResource。 ITestResource 在已发布的头文件 ITestResource.h 中定义,如下所示:
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*/
在本示例中,类 MyTestResource 实现 ITestResource COM 接口。 在 ITestResource.h 中,还将找到定义的“必备”属性的列表。 应该可以使用 GetGuid(..) 获取测试资源的 GUID,并使用 GetValue(...) 获取资源的名称、ID 和类型。如果 TestResource 中缺少其中任何一项,TAEF 会将其视为无效,并且不会维护它的信息。(请参阅下面的“生成资源列表”部分)。
为设备支持创作 - 指定与资源相关的元数据
若要指定测试模块具有与测试资源相关的测试方法,必须将模块级别元数据属性 'TestResourceDependent" 设置为“true”。 该属性由测试模块中的所有类和这些类中的所有测试方法继承。 如果模块中的任何测试方法都与测试资源无关,则应将元数据值显式重新设置为 false。 与测试资源相关的其他所有测试方法都必须使用测试资源的“ID”和/或“Type”提供选择查询。
以下是示例资源列表的一些快速示例“ResourceSelection”,以及它们各自的含义:
- "@Id='HD*'":用以“HD”开头的 ID 匹配每个资源
- "@Type='PCI'":匹配类型为“PCI”的每个资源
- "@Id='PCI*' OR @Id='HD*'":匹配以“PCI”开头或以“HD”开头的每个资源
- "@Type='PCI' 和 @id='*37'":为每个资源匹配一个名称以“37”结尾的“PCI”类型的资源
在我们的示例代码中,如下所示:
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()
...
};
在上面的示例中,你将看到该模块标记为“TestResourceDependent”。 通过将“TestRssourceDependent”元数据设置为“false”,NoTestResourceTest 被明确标记为与任何测试资源无关。 所有其他测试方法都为它们感兴趣的测试资源指定了一个选择标准。
选择条件语法与可用于 TAEF 的命令行选择查询语法非常相似。 然而,在资源选择的情况下,它仅限于使用资源 ID 和类型。 由于资源 ID 是一个字符串,因此需要将其括在单引号中。 可以在 ID 值的规范中使用通配符“*”或“?”。 在上面的示例中,在 OneHDAudioTest 中,资源选择指定与 ID 以“HD”开头的任何资源匹配。 同样,在 HDorPCITest 的情况下,资源选择将与 ID 以“HD”开头或以“PCI”开头的任何资源匹配。 请务必注意,资源选择不区分大小写,即“pci”、“Pci”和“PCI”都将被视为相同的。
根据资源选择,TAEF 将为与选择匹配的每个测试资源重新调用测试方法以及测试级设置和清理方法(已指定)一次。 以下部分将详细介绍如何指定资源列表,并将其提供给 TAEF,以及测试方法如何检索下一节中的资源。
为设备支持创作 - 生成资源列表
一旦 TAEF 遇到 TestResourceDependent 测试模块,它将查找并调用 dll 导出的方法 BuildResourceList。 它是在 BuildResourceList 的实现中,用户可以在其中创建新的测试资源,并将其添加到作为参数传递给 BuildResourceList 的接口。 让我们看一下这个方法在我们示例中的实现:
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 接受对 WEX::TestExecution::ResourceList 的引用作为其参数。 ResourceList 在已发布的头文件 ResourceList.h 中定义。 使用 ResourceList 上的 Add(...) 方法,用户可以添加为 TAEF 发现或创建的所有测试资源来管理和使用。 上面的示例添加了 5 个这样的测试资源。
如果要添加的测试资源无法返回资源的“Name”、“Id”、“Type”或 GUID,则 Add 方法将失败。
ResourceList 将在测试模块的整个生命周期内进行维护,也就是说,直到所有测试方法和清理方法都执行完毕。 如果 BuildResourceList 返回 FAILED HRESULT 值,则测试模块中所有与资源相关的测试方法都会记录为阻止而不执行。 所有非测试资源都将被执行。
BuildResourceList 在测试模块中的任何其他方法之前被调用。 在生成资源列表(在 BuildResourceList 中)后,使用“ResourceSelection”元数据来匹配资源列表中的可用资源。 如果找到匹配项,则会调用所有安装方法(模块、类、测试顺序),然后调用测试方法本身。 每次测试调用后都会调用测试级清理方法。
在后台,TAEF 保留了应用资源选择的资源列表。 例如,对于 OneHDAudioTest 测试方法,ID 为“HDAudio-deviceid-1”和“HDAudio-deviceid-2”的测试资源将匹配“HD*”,并且对于其中每个方法,TAEF 都将重新调用该测试方法(每种方法调用一次)。 还将有一个与每次测试调用相关联的隐式索引。 因此,你将看到<命名空间限定符>OneHDAudioTest#0 和<命名空间限定符>OneHDAudioTest#1 作为两个调用。
为设备支持创作 - 在测试方法中检索设备
前面的部分介绍了如何在模块、类和测试方法级别添加必要的元数据。 同时还探讨了如何定义自定义测试资源,以及如何在 BuildResourceList 的实现中将其添加到 ResourceList。 接下来的下一部分是检索测试方法中的资源。 让我们来看一下示例中的一种简单测试方法:
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 }
在 OneHDAudioTest 中,资源选择每次选择一个资源 ID 以“HD”开头的测试资源。 ResourceList.h 中定义的静态类 Resources 提供了用于检索计数的 API,以及在任何给定的测试调用期间可用的实际资源。 在这种情况下,如上面的示例中第 4 行、第 9 行和第 13 行所示, Resources::Count() 给出了当前调用测试方法期间可用的测试资源的数量。 在此测试方法中,应为 1。 可以使用 TAEF (Verify.h) 中可用的 VERIFY 宏来验证此值。 如你所知,如果任何验证调用在基于异常的 TAEF 测试中失败,则执行将在该点终止,并将测试方法标记为“失败”。
接下来,使用 Resources::Item(...) API,并传入检索资源的索引(在这种情况下,由于调用期间只有一个测试资源可用,索引将始终为 0),因此可以检索测试资源。 测试方法可以根据需要进一步使用检索到的测试资源进行测试。
所有测试方法都遵循相同的基本原则。 查看示例中的其他测试方法,以便更好地了解。
执行与测试资源相关的测试模块
现在创作并生成了与测试资源相关的测试,现在可以使用 TAEF 执行它。 需要注意的关键点是,TestResourceDependent 测试只能以 inproc 执行。 这意味着,即使你没有明确指定 "/inproc" 开关,只要 TAEF 发现与测试资源相关的测试模块,它就会被添加。 如你所知,当存在“/inproc”开关时,在给定的 TAEF 执行中只能执行来自一个测试模块的测试。 这意味着,如果测试模块与资源相关,则无法在命令行指定多个测试模块。
若要实际执行测试模块中的所有测试,只需运行:
te Examples\Cpp.TestResource.Example.dll
在不实际运行测试方法的情况下,只获取所有测试方法调用以及数据和元数据组合的列表的一种有用方法是在命令行中使用 /listproperties 开关。 我们来看一看输出。
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
请注意,在每次调用与测试资源相关的测试方法期间,将隐式索引添加到测试方法名称中。 ResourceSelection 属性后面显示的是将对测试方法可用的所有资源的列表,按照它们可用的顺序排列。 例如,在第三次调用 HDAudioHDAudioPCITest (HDAudioHDAudioPCITest#2) 的情况下,HDAudio-deviceid-1 将是 Resources::Item(...) 中索引 0 处的可用资源。
通过使用 TAEF 中提供的命令行选择查询语言,可以更具体地了解你感兴趣的测试调用。 例如,若要选择测试资源“PCI-deviceid-3”可用的所有测试方法调用,可以使用选择条件:
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
同样,若要按名称选择特定的测试方法(请注意,测试方法名称与末尾附加的调用索引一起是完全限定的),可以使用选择查询,如下所示:
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
请注意,在上述示例的第三行中,隐式 inproc 添加了警告。 上述选择查询与选择查询具有相同的效果:/select:"@Name='*OneHDAudio*' And @Resource:Index=1"。 还可以使用资源的名称或类型(或 ID,如上所示)选择资源。 例如,/select:"@Name='*PCIHDAudioTest*' 和 @Resource:Name='PCI3'" 将选择测试方法 PCIHDAudioTest#4 and PCIHDAudioTest#5。
读者可以在命令提示符下尝试这些和其他选择查询。