PICT 数据源

在继续执行本部分之前,请确保熟悉 TAEF 的基本执行,并了解如何使用 TAEF 编写测试。

PICT 背景和引用

PICT 代表成对独立组合测试 (Pairwise Independent Combinatorial Testing)。 PICT 允许单独为每个参数指定变体。 例如,如果 API 测试依赖于两个参数:FileName 和 FileExtension,则可以考虑为 FileName 和 FileExtension 单独传递的可能变体,如下所示:

  • FileName: a, z12390, Realllyreallyreallylonglonglonglonglonglonglonglonglonglong, 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:” ,并为此提供测试方法的 DataSource。 对于托管测试,就像使用 TAEF 进行任何其他数据驱动测试一样,必须提供 TestContext 属性获取和设置方法,并在类中具有相同私有实例。

如果要将命令选项传递给 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 输出作为数据生成的所有测试方法的列表, /listproperties 获取测试方法名称的列表以及它们关联的元数据和数据值等。 在开始之前要注意的关键是确保 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 相同的位置(并将资源名称命名为与文件名相同)来利用此设计。 完成测试后,将文件移回代码目录,然后重新编译以嵌入资源。