在继续本部分之前,请确保熟悉 TAEF 的基本执行并知道如何使用它创作测试。
PICT 背景和参考
PICT 代表成对独立组合测试。 PICT 允许单独为每个参数指定变体。 例如,如果 API 测试依赖于两个参数:FileName 和 FileExtension,则可以单独考虑为 FileName 和 FileExtensions 传递的可能变体,如下所示:
- FileName: a, z12390, Realllyreallyallylonglonglonglonglonglonglong, normallength
- FileExtension:txt、png、bat、doc、exe、bmp、wav
现在,可以看到上述 (4 X 7 = 28) 的暴力组合扩展很容易越界,因为你想到要添加到列表的更多变体。 在此类测试用例方案中, PICT 可以通过生成一组紧凑的参数结果来增加大量价值,以获得对输入参数的全面组合覆盖。
TAEF 中的 PICT 支持
TAEF 为基于 PICT 的测试提供内置支持。
若要利用此功能,请像平时一样为pict.exe编写输入模型文件。 请参阅上面提到的示例文件夹中的 *.txt 文件。 如果 PICT 按预期方式在模型文件上执行,最好先在命令提示符下尝试,如下所示:
pict.exe <model file> [/e:<seed file>]
Pict.exe可用于 TAEF 最新版本共享上的其余二进制文件。
你已完成为 PICT 创作模型文件 (和种子文件) ,并在命令提示符下针对pict.exe进行了验证,现在可以标记测试,让 TAEF 知道它们是 PICT 驱动的测试。 如果你熟悉 TAEF 中提供的基于表的数据驱动测试,你会发现这非常相似。
本机代码:
1 class PictExample
2 {
3 TEST_CLASS(PictExample)
4
5 BEGIN_TEST_METHOD(SimpleTest)
6 TEST_METHOD_PROPERTY(L"DataSource", L"pict:PictExample.txt")
7 END_TEST_METHOD()
8
9 BEGIN_TEST_METHOD(TestWithSeed)
10 TEST_METHOD_PROPERTY(L"DataSource", L"pict:TestWithSeed.txt")
11 TEST_METHOD_PROPERTY(L"Pict:SeedingFile", L"TestWithSeed.sed")
12 TEST_METHOD_PROPERTY(L"Pict:Timeout", L"00:01:30")
13 END_TEST_METHOD()
14
15 BEGIN_TEST_METHOD(TestWithFunction)
16 TEST_METHOD_PROPERTY(L"DataSource", L"pict:TestWithFunction.txt")
17 END_TEST_METHOD()
18 };
托管代码:
1 [TestClass]
2 public class CSharpPictExample
3 {
4 [TestMethod]
5 [DataSource("pict:ConstraintsTest.txt")]
6 [TestProperty("Pict:SeedingFile", "ConstraintsTest.seed")]
7 public void ConstraintsTest()
8 {
9 ...
10 }
11
12 [TestMethod]
13 [DataSource("pict:SumofSquareRoots.txt")]
14 public void SumOfSquareRoots()
15 {
16 ...
17 }
18
19 public TestContext TestContext
20 {
21 get { return m_testContext; }
22 set { m_testContext = value; }
23 }
24
25 private TestContext m_testContext;
26 }
如上述示例所示,需要将模型文件的名称指定为 DataSource。 必须在模型文件的名称前面加上“pict:” ,并将其作为测试方法的数据源提供。 对于托管测试,就像使用 TAEF 进行任何其他数据驱动测试一样,必须提供 TestContext 属性 get 和 set 方法,并在类中具有相同 的私有实例。
如果要将命令选项传递给 PICT,可以使用元数据实现此目的。 使用下表将 Pict.exe 的命令选项映射到 TAEF 元数据。
pict.exe 命令语法 | 本机 TAEF 元数据语法 | 托管 TAEF 元数据语法 |
---|---|---|
/o:3 | TEST_METHOD_PROPERTY (L“Pict:Order”,L“3”) | [TestProperty (“Pict:Order”, “3”) ] |
/D: | TEST_METHOD_PROPERTY (L“Pict:ValueSeparator”, L“,”) | [TestProperty (“Pict:ValueSeparator”, “,”) ] |
/a: | TEST_METHOD_PROPERTY (L“Pict:AliasSeparator”, L” | |
/n:~ | TEST_METHOD_PROPERTY (L“Pict:NegativeValuePrefix”, L“~”) | [TestProperty (“Pict:NegativeValuePrefix”, “~”) ] |
/e:test.seed | TEST_METHOD_PROPERTY (L“Pict:SeedingFile”, L“test.seed”) | [TestProperty (“Pict:SeedingFile”, “test.seed”) ] |
/r | TEST_METHOD_PROPERTY (L“Pict:Random”, L“true”) | [TestProperty (“Pict:Random”, “true”) ] |
/r:33 | TEST_METHOD_PROPERTY (L“Pict:RandomSeed”, L“33”) | [TestProperty (“Pict:RandomSeed”, “33”) ] |
/c | TEST_METHOD_PROPERTY (L“Pict:CaseSensitive”, L“true”) | [TestProperty (“Pict:CaseSensitive”, “true”) ] |
上述任何元数据都可以在命令提示符处、DataSource 属性中设置,也可以设置为测试、类或模块级别的元数据,并按该顺序优先。 若要在命令提示符下设置它,请使用语法:
te.exe <test dll> /Pict:Order=3 /Pict:SeedingFile=test.seed
若要在 DataSource 属性中设置元数据,请在模型文件名后面追加一个问号字符 (?) 然后追加一组与和分隔的元数据名称 = 元数据值对。 使用此方法时,元数据名称的“Pict:”前缀是可选的。 以下是示例:
TEST_METHOD_PROPERTY(L"DataSource", L"Pict:model.txt?Order=3&CaseSensitive=true&Random=true")
在后台,TAEF 将向 PICT 提供输入模型文件和命令选项,并获取结果。 如果 PICT 生成任何错误或警告,则会看到 TAEF 记录为警告。 对于 PICT 生成的每个结果输出行,TAEF 将重新调用相关测试。
设置“Pict:RandomSeed”值会将“Pict:Random”的默认值从 false 更改为 true。 这样,就可以将“Pict:Random”显式设置为 false,使 TAEF 忽略“Pict:RandomSeed”。
允许对模型文件执行PICT.exe的默认超时,指定的种子文件输入为 5 分钟。 如果模型文件涉及较多,并且PICT.exe返回结果需要超过 5 分钟的时间,可以通过指定 “Pict:Timeout” 元数据来替代上述 CPP 示例中所示的此超时。 在此示例中,通过标准 TAEF 超时格式指定 1.5 分钟的超时。 与其他 PICT 元数据一样,“Pict:Timeout”元数据是继承的,因此可以为整个类或模块指定。
可以在给定调用期间从测试方法及其关联的设置和清理方法访问数据值,其方式与使用 TAEF 进行基于表的数据驱动测试的方式相同 - 将 TestData 类用于本机代码,并将 TestContext 用于托管代码,如下所示:
本机代码:
1 void PictExample::SimpleTest()
2 {
3 String valueA;
4 if (SUCCEEDED(TestData::TryGetValue(L"A", valueA)))
5 {
6 Log::Comment(L"A retrieved was " + valueA);
7 }
8
9 String valueB;
10 if (SUCCEEDED(TestData::TryGetValue(L"B", valueB)))
11 {
12 Log::Comment(L"B retrieved was " + valueB);
13 }
14
15 String valueC;
16 if (SUCCEEDED(TestData::TryGetValue(L"C", valueC)))
17 {
18 Log::Comment(L"C retrieved was " + valueC);
19 }
20
21 unsigned int index;
22 if (SUCCEEDED(TestData::TryGetValue(L"index", index)))
23 {
24 Log::Comment(String().Format(L"At index %d", index));
25 }
26 }
托管代码:
1 [TestClass]
2 public class CSharpPictExample
3 {
4 [TestMethod]
5 [DataSource("pict:ConstraintsTest.txt")]
6 public void ConstraintsTest()
7 {
8 Log.Comment("A is " + m_testContext.DataRow["A"]);
9 Log.Comment("B is " + m_testContext.DataRow["B"]);
10 Log.Comment("C is " + m_testContext.DataRow["C"]);
11 Log.Comment("D is " + m_testContext.DataRow["D"]);
12
13 UInt32 index = (UInt32)m_testContext.DataRow["Index"];
14 Log.Comment("At index " + index.ToString());
15 }
16
17 [TestMethod]
18 [DataSource("pict:SumofSquareRoots.txt")]
19 public void SumOfSquareRoots()
20 {
21 Log.Comment("A is " + m_testContext.DataRow["A"]);
22 Log.Comment("B is " + m_testContext.DataRow["B"]);
23
24 UInt32 index = (UInt32)m_testContext.DataRow["Index"];
25 Log.Comment("At index " + index.ToString());
26 }
27
28 public TestContext TestContext
29 {
30 get { return m_testContext; }
31 set { m_testContext = value; }
32 }
33
34 private TestContext m_testContext;
35 }
与 TAEF 中的任何数据驱动测试一样,“索引”是保留的,不应用作参数名称。 索引隐式引用测试方法调用的索引,如果测试需要,可以从测试方法访问索引。
另请注意,对于基于 PICT 的测试,假定所有参数的数据类型为 WEX::Common::String (本机) 、String (托管) 或VT_BSTR (脚本) 。 转换和解释由用户决定。
完成使用 TAEF 创作基于 PICT 的测试后,可以从命令提示符调用它并应用 TAEF 提供的所有命令功能:如 /list 获取将使用 PICT 输出作为数据生成的所有测试方法的列表, /list 属性 获取测试方法名称的列表以及它们关联的元数据和数据值等。 在开始之前,需要注意的关键是确保pict.exe在你的路径中。
以下是一些示例:
te Examples\CPP.Pict.Example.dll /list /name:*SimpleTest*
Test Authoring and Execution Framework v2.9.3k for x86
f:\ Examples\CPP.Pict.Example.dll
WEX::TestExecution::Examples::PictExample
WEX::TestExecution::Examples::PictExample::SimpleTest#0
WEX::TestExecution::Examples::PictExample::SimpleTest#1
WEX::TestExecution::Examples::PictExample::SimpleTest#2
WEX::TestExecution::Examples::PictExample::SimpleTest#3
WEX::TestExecution::Examples::PictExample::SimpleTest#4
WEX::TestExecution::Examples::PictExample::SimpleTest#5
WEX::TestExecution::Examples::PictExample::SimpleTest#6
WEX::TestExecution::Examples::PictExample::SimpleTest#7
WEX::TestExecution::Examples::PictExample::SimpleTest#8
WEX::TestExecution::Examples::PictExample::SimpleTest#9
WEX::TestExecution::Examples::PictExample::SimpleTest#10
WEX::TestExecution::Examples::PictExample::SimpleTest#11
WEX::TestExecution::Examples::PictExample::SimpleTest#12
WEX::TestExecution::Examples::PictExample::SimpleTest#13
WEX::TestExecution::Examples::PictExample::SimpleTest#14
WEX::TestExecution::Examples::PictExample::SimpleTest#15
WEX::TestExecution::Examples::PictExample::SimpleTest#16
WEX::TestExecution::Examples::PictExample::SimpleTest#17
WEX::TestExecution::Examples::PictExample::SimpleTest#18
WEX::TestExecution::Examples::PictExample::SimpleTest#19
WEX::TestExecution::Examples::PictExample::SimpleTest#20
WEX::TestExecution::Examples::PictExample::SimpleTest#21
WEX::TestExecution::Examples::PictExample::SimpleTest#22
WEX::TestExecution::Examples::PictExample::SimpleTest#23
若要详细了解 /select 和 /name) (选择条件,请参阅选择 wiki 页面。
te Examples\Csharp.Pict.Example.dll /listproperties /select:"@Name='*SumofSquare*'
and @Data:index>10
Test Authoring and Execution Framework v2.9.3k for x86
f:\ Examples\CSharp.Pict.Example.dll
WEX.Examples.CSharpPictExample
WEX.Examples.CSharpPictExample.SumOfSquareRoots#11
Property[DataSource] = pict:SumofSquareRoots.txt
Data[a] = 1
Data[b] = ~-1
WEX.Examples.CSharpPictExample.SumOfSquareRoots#12
Property[DataSource] = pict:SumofSquareRoots.txt
Data[a] = 2
Data[b] = ~-1
上面的示例演示如何使用 索引进行选择。 还可以选择基于数据值进行选择。
te Examples\Csharp.Pict.Example.dll /listproperties /select:"@Name='*SumofSquare*'
and (@Data:A='1' and @Data:B='1')"
Test Authoring and Execution Framework v2.9.3k for x86
f:\ Examples\CSharp.Pict.Example.dll
WEX.Examples.CSharpPictExample
WEX.Examples.CSharpPictExample.SumOfSquareRoots#8
Property[DataSource] = pict:SumofSquareRoots.txt
Data[a] = 1
Data[b] = 1
PICT 结果缓存
某些模型文件可能会变得非常复杂,并且可能需要更长的时间才能由Pict.exe进行处理。 TAEF 尝试通过在给定执行Te.exe期间缓存结果来减少结果的处理时间。 如果同一执行运行中的后续测试引用相同的模型和种子文件组合,TAEF 将使用缓存的结果。 默认情况下,每次执行结束时都会删除缓存的结果。
如果要在后续运行中继续利用缓存的结果,可以在执行期间在命令提示符处指定“/persistPictResults”选项。 每当为命令指定“/persistPictResults”时,第一次执行实际上将执行pict.exe并且可能需要很长时间,但所有后续运行都将在模型和种子文件未修改的情况下使用缓存的结果。 注意:需要继续为后续运行指定“/persistPictResults”。 未指定的任何后续运行都将删除该运行结束时缓存的结果。
如果默认情况下想要保留 PICT 结果并使用缓存数据,则可以将其设置为te_cmd环境变量的一部分,如下所示,无需在每次运行时指定它。 有关te_cmd的更多详细信息,请参阅 执行测试 。
set te_cmd = /persistPictResults
缓存的结果文件存储在 %temp% 目录中名为“TAEF-PICT”的文件夹中(如果Te.exe有权访问它),或者存储在启动Te.exe的当前执行目录中。 只有在执行期间按 Ctrl + C,才可能导致结果处于不一致状态。 在这种情况下,TAEF 将尝试删除缓存的结果,但如果无法删除,则会看到错误。 此错误将提示删除缓存的结果位置。 如果不这样做,可能会导致后续测试中出现未定义或错误的行为。
借助 TAEF 中的内置 PICT 支持,现在可以在测试自动化中充分利用 PICT 中的功能和 TAEF 中的功能。
DataSource 即资源
可以在测试模块中添加 PICT 模型和种子设定文件作为资源。
在本机代码中,可通过指定资源名称而不是 DataSource 元数据中的文件名来完成此操作。 以下是示例:
BEGIN_TEST_METHOD(ResourceNameDataSource)
TEST_METHOD_PROPERTY(L"DataSource", L"Pict:MyModelResourceName?SeedingFile=MySeedingResourceName")
END_TEST_METHOD()
“MyModelResourceName”和“MySeedingResourceName”是在 .rc 文件中定义的资源名称。 资源类型需要为 DATAFILE,这与需要DATASOURCE_XML资源类型的 表数据源 不同。
MyModelResourceName DATAFILE "model.txt"
MySeedingResourceName DATAFILE "seed.txt"
DataSource 元数据值将保持与模型为文件时的相同。 同样,在本机代码中,可以使资源名称与文件名相同。 TAEF 将首先查找是否存在具有 DataSource 名称的实际文件。 如果找不到该文件,则继续查找测试模块的资源。 由于更改存储在资源中的 DataSource 需要重新编译,因此可以在开发 (并将资源名称命名为与) 的文件名相同时,通过将 DataSource 文件复制到与测试 dll 相同的位置来利用此设计。 完成测试后,将 (不要将) 文件复制回代码目录,然后重新编译以嵌入资源。