本主题说明如何在测试期间使用预定义或自动生成的数据源值。针对不同数据集运行测试能够让您轻松增加测试量和覆盖率。

章节目录:

在桩函数中使用数据源

您配置的在 C++test 中使用的任何数据源都可以在桩函数中使用。详细信息请参阅在桩函数中使用数据源

添加数据源

可以使用 GUI 向导在 C++test 中定义数据源。在向导中,通过逗号分隔值文件(.csv)、Excel 电子表格(.xls)、或 C++test 管理的数据源表指定数据源。在测试用例执行过程中,测试用例会使用从特定数据源收集的值。

托管数据源可以通过测试用例浏览器在项目级别(对所有项目测试套件可见)或在单个测试套件级别(仅由特定的测试套件使用)定义。此外,还可以在解决方案级别创建托管数据源)。

在项目/测试套件级别添加已有数据源

在项目/测试套件级别创建托管数据源的步骤:

  1. 在测试用例浏览器中选择项目或测试用例节点。
  2. 右键点击选择的节点,然后从快捷菜单中选择新建> 数据源
  3. 指定数据源类型。

  4. 配置数据源

 使用空引用而不是空字符串

若要使用空引用而非空字符串,应从特殊值前缀字段选择 $,然后在 CSV 文件中输入 NULL 之前使用 $ 前缀;例如:
$NULL

在解决方案级别添加已有数据源


在 解决方案 级别创建托管数据源的步骤:

  1. 右键点击测试用例浏览器视图中的全局数据源节点,然后选择新建> 数据源



  2. 定义新的托管数据源。

自动生成新的数据源

C++test 可以生成逗号分隔值文件(.csv)或包含自动生成的数据源值的 C++test 管理表数据源。

有关在测试用例编辑器中自动生成新数据源的信息,请参阅使用数据源参数化在测试用例编辑器中添加的测试用例

如果在测试用例向导中配置测试用例:

  1. 点击测试用例向导编辑器页面的自动生成按钮。
  2. 在打开的自动生成窗口中指定所需的设置。


生成数据源时,C++test 为每个具有可编辑值(布尔、整数、浮点和字符串类型)的前置和后置条件创建一个单独的列。该数据源在测试套件级别生成。

生成后,生成的数据源就可以用于参数化测试套件中的其他测试用例。

使用数据源值参数化测试用例

使用数据源参数化在测试用例编辑器中添加的测试用例 

您可以使用数据源值来参数化通过测试用例编辑器创建的测试用例(请参阅使用测试用例编辑器添加测试套件和测试用例)。这些值可以在内置到测试用例中的数据源表中提供,也可以在外部数据源中提供。

  1. 打开测试用例浏览器视图,右键点击测试套件
  2. 选择新建> 使用测试用例编辑器…
  3. 创建下面的测试用例下拉列表选择一个函数。
  4. 点击创建新的参数化测试用例按钮()打开数据源选择对话框。
  5. 选择要使用的数据源。以下选项可用:
    内置的表 - 向测试用例添加一个指定参数化值的表(有关参数 API 的详细信息,请参阅添加测试用例参数化值,您可以用来访问内置表中指定的值)。
    外部数据源 - 自动生成用于指定参数化值的外部数据源:逗号分隔值文件(.csv)或表格数据源 如果选择此选项,应在打开的自动生成窗户中指定所需的设置并点击确定该数据源在测试套件级别生成。

         
  6. 保存测试用例,将其添加到测试套件中。

使用数据源参数化在测试用例向导中编写的测试用例

您可以使用数据源值来参数化已有的(自动生成的或用户定义的)测试用例,以及在测试用例向导中编写测试用例时定义测试用例值。数据源值可以取自上文描述的 C++test 中定义的任何数据源。

注意

C++test 无法自动验证由数据源值参数化的测试用例执行产生的未验证的结果和失败的断言。这是因为它通常也要求使用通过数据源参数化的期望结果。

通过测试用例向导配置数据源使用

使用测试用例向导添加从先前定义的托管数据源中提取值的新测试用例:

  1. 在测试用例浏览器中,右键点击测试套件节点,然后从快捷菜单中选择新建> 使用测试用例向导
  2. 在第一个页面中,指定源文件(编译单元)和要为其添加测试用例的函数,然后输入测试用例的名称。
  3. 点击下一步打开下一个向导页。
  4. 勾选使用数据源复选框,选择相应数据源。



  5. 使用 GUI 控件指定测试用例的输入和期望的输出值来配置测试用例。
    • 要将数据源值用于特定的前置或后置条件,可双击相关节点,然后选择相应的数据源列名。数据源值以花括号括起来的列名形式在组合框中列出,例如“{myColumnName}”。
  6. 点击完成生成测试用例。新的测试用例将添加到测试套件中,生成的源代码将在编辑器中打开。

通过测试用例代码配置数据源使用

使用先前定义的托管数据源参数化已有(自动生成或用户定义)测试用例:

  1. 指定要与注册宏一起使用的数据源
    CPPTEST_TEST_DS(<TEST_CASE_NAME>,
    CPPTEST_DS("<MANAGED_DATA_SOURCE_NAME>"));
  2. 指定如何将数据源值与 CPPTEST_DS* 宏一起使用(在用于访问数据源值的宏中有所说明)。

示例

例如,要使用 Excel 工作表中的值参数化已有测试用例,我们之后将该工作表称为“MyDataSourceForSum”:

  1. 打开项目。
  2. 确保已将 Excel 工作表添加为托管数据源:
    1. 在测试用例浏览器中,右键点击项目节点,从快捷菜单中选择新建> 数据源
    2. 选择 Excel,然后点击完成。
    3. 为数据源输入一个有意义的名称(例如“MyDataSourceForSum”)。
    4. 输入您的 .xsl 文件的位置。
    5. (可选)点击显示列并快速验证列名。
    6. 点击确定。新的数据源将显示在测试用例浏览器中。
  3. 在测试用例浏览器中,双击您要参数化的测试用例。
  4. 找到测试用例注册行(在测试套件文件中)。例如:

    ...
    CPPTEST_TEST(sumTest1);
    ...
  5.  将注册类型更改为使用数据源(your_Data_Source_name):

    ...
    CPPTEST_TEST_DS(sumTest1, CPPTEST_DS("MyDataSourceForSum")); 
    ...
  6. 进入测试用例定义并添加代码,告诉 C++test 该如何使用数据源列中的值。使用用于访问数据源值的宏中描述的宏。
    例如:
    ...
    /* CPPTEST_TEST_CASE_BEGIN sumTest1 */     
    void MyTestSuite::sumTest1()
    {
	int iVal = CPPTEST_DS_GET_INTEGER("i"); 
	int jVal = CPPTEST_DS_GET_INTEGER("j");
	int expectedResult = CPPTEST_DS_GET_INTEGER("result"); 
	CPPTEST_ASSERT_INTEGER_EQUAL(expectedResult, sum(iVal, jVal));
    }
    /* CPPTEST_TEST_CASE_END sumTest1 */    
    ...

执行测试用例时,它将使用来自“MyDataSourceForSum”Excel 类型数据源的值进行参数化。

用于访问数据源值的宏

以下宏可用于访问数据源中的值。每个宏都采用参数 NAME,该参数指定了数据源列的唯一标识符。

目的...使用此宏...注意
返回以 null 结尾的字符串值

const char*
CPPTEST_DS_GET_CSTR(const char* NAME)

N/A
返回一个字符值

char

CPPTEST_DS_GET_CHAR(const char* NAME)

N/A
返回一个整数值

long long
CPPTEST_DS_GET_INTEGER(const char* NAME)

N/A
返回一个无符号整数值unsigned long long CPPTEST_DS_GET_UINTEGER(const char* NAME)N/A
返回一个浮点值long double
CPPTEST_DS_GET_FLOAT(const char* NAME)
N/A
返回一个布尔值int
CPPTEST_DS_GET_BOOL(const char* NAME)
N/A
返回内存缓冲区const char*
CPPTEST_DS_GET_MEM_BUFFER (const char* NAME, unsigned int* SIZE_PTR)
如果 SIZE_PTR 不为空,则缓冲区的大小将存储在相应位置。
返回一个枚举值

<scoped enum name>

CPPTEST_DS_GET_ENUM(<scoped enum name>, const char* NAME)

<scoped enum name> 是枚举的全名,包括所有命名空间名称。例如: INNER_NS::MyEnumeration, INNER_NS::MyClass::MyEnumeration 
从 SOURCE 数组返回值CPPTEST_DS_GET_VALUE(SOURCE)

应将数组类型的变量指定为 SOURCE 参数:

每次执行测试用例后,自动提取值的行号会自动增加。

返回当前迭代(行号)unsigned int
CPPTEST_DS_GET_ITERATION( )
可用于确定当前迭代/行号。
如果 'name' 列存在于当前数据源的当前迭代中,则返回非零值。int
CPPTEST_DS_HAS_COLUMN(const char* name)
可用于测试用例特定行为的桩函数(请参阅在桩函数中使用数据源)。如果不使用数据源,则返回零。

数据源值的格式

下表提供了特定类型数据源值的支持格式相关的信息:

数据源类型C++test API 函数支持的格式
布尔CPPTEST_DS_GET_BOOLEAN()

如果为 true:

    • true
    • 非零整数常量;例如 1

如果为 false:

    • false
    • 0
有符号整数CPPTEST_DS_GET_INTEGER()

整数的十进制表示法(可以使用- 或 + 号作为前缀);例如:

    • 0
    • 1
    • -200
    • +55

前缀为 0x 或 0X 的整数十六进制表示法(可以使用- 或 + 号作为前缀);例如:

    • 0x1a
    • -0XFF
    • +0x12

前缀为 0 的整数八进制表示法(可以使用- 或 + 号作为前缀);例如:

    • 0711
    • -0123
    • +055

前缀为 0b 或 0B 的整数二进制表示法(可以使用- 或 + 号作为前缀);例如:

    • 0b01010101
    • -0B1111
    • +0b11
无符号整数CPPTEST_DS_GET_UINTEGER()

整数的十进制表示法;例如:

    • 0
    • 1
    • 200

前缀为 0x 或 0X 的整数十六进制表示法;例如:

    • 0x1a
    • 0XFF

前缀为 0 的整数八进制表示法;例如:

    • 0711
    • 0123

前缀为 0b 或 0B 的整数二进制表示法;例如:

    • 0b01010101
    • 0B1111
浮点CPPTEST_DS_GET_FLOAT()

浮点值的实际格式取决于所使用的编译器的配置——CPPTEST_STR_TO_FLOAT / CPPTEST_SCANF_FLOAT /
CPPTEST_SCANF_FLOAT_FMT 宏的实际实现。在大多数情况下,十进制数字序列可能包含基数字符(小数点,取决于语言环境,通常是“.”)。

此外,后面也可以跟一个十进制指数。十进制指数由“E”或“e”组成,后跟可选的加号或减号,然后是一串非空的十进制数字,表示乘以 10 的幂。

示例:

    • 100
    • 1.5
    • -3.14159
    • 0.44E7
    • 99.99e-15
charCPPTEST_DS_GET_CHAR()

使用的字符;例如:

    • a
    • 0
    • $

此外,应使用以下类似 C 语言风格的转义序列来处理特殊字符:

    • \n
    • \t
    • \v
    • \b
    • \r
    • \f
    • \a
    • \\
    • \'
    • \"

对于不可打印的字符,可以使用字符的八进制(1-3 个前缀为 \ 的数字)或十六进制(1-2 个前缀为 \x 的数字)表示法;例如:

    • \13
    • \017
    • \x0A
stringCPPTEST_DS_GET_CSTR()

要使用的字符串;例如:

    • abcdefgh
    • qaz123
    • Hello world!

此外,应使用以下类似 C 语言风格的转义序列来处理特殊字符:

    • \n
    • \t
    • \v
    • \b
    • \r
    • \f
    • \a
    • \\
    • \'
    • \''

示例:

    • Hello, \"world\"!

要在字符串中使用不可打印的字符,可以使用字符的八进制(1-3 个前缀为 \ 的数字)或十六进制(1-2 个前缀为 \x 的数字)表示法;例如:

    • \13
    • \017
    • \x0A

为了将空值定义为数据源中的 C 字符串值,可以配置托管数据源识别一些字符;例如 $ 作为特殊值前缀,可以在数据源中使用带有该前缀字符的 NULL;例如:

    • $NULL

请注意,这只能用于 UI 管理的数据源(用 CPPTEST_DS("ds_name") 宏注册的测试用例)。

数据缓冲区CPPTEST_DS_GET_MEM_BUFFER()使用与字符串类型相同的格式(请参阅上文)。
枚举值CPPTEST_DS_GET_ENUM()

可以使用简单的枚举值名称或包含所有命名空间名称的完整名称。例如,如果在 ::INNER_NS::MyClass::DaysEnumeration 中定义 MON 枚举值,您可以输入 MON 或 ::INNER_NS::MyClass::MON。

要在数据源和参数步骤中使用枚举值,应启用测试配置选项:“启用枚举数据自动生成”。您可以在以下位置找到此选项:“测试配置 > 执行选项卡 > 常规选项卡 > 插桩模式 > 编辑 > 插桩功能 > 高级选项”。


下表提供了有关使用特定数据源类型格式化数据源值的信息:

数据源类型数据源注册宏其他信息
CSV 文件(托管数据源)CPPTEST_DS()

数据源值可以用引号括起来(可以在数据源配置中定义引号);例如:

    • "Hello world!"

这对于需要在值中使用分隔符或者引号本身的情况而言是必需的。针对后面一种情况,需要将用作数据源值中元素的引号重复使用;例如:

    • "Hello world!"
    • "Hello, \""world\""!"
Excel 电子表格(托管数据源)CPPTEST_DS()

不需要进行特定的 Excel 值准备。注意,需要格式化数据以用于上述特定类型。

为了确保 C++test 正确处理值,您可以对电子表格中的所有单元格使用文本格式。例如,通过这种方式,您可以确保整数值的八进制表示形式被正确处理。

表格(托管数据源)CPPTEST_DS()不需要进行特定的表格值准备。注意,需要格式化数据以用于上述特定类型。
CSV fileCPPTEST_DS_CSV()

数据源值可以用引号括起来(可以在数据源配置中定义引号);例如:

    • "Hello world!"

这对于需要在值中使用分隔符或者引号本身的情况而言是必需的。针对后面一种情况,需要将用作数据源值中元素的引号重复使用;例如:

    • "Hello, world!"
    • "Hello, \""world\""!"
源代码数组CPPTEST_DS_ARRA Y()不需要进行数组特定的值准备。注意,需要格式化数据以用于上述特定类型。

探索可用的数据源

查看/修改数据源配置

查看或编辑现有数据源配置的步骤:

  • 右键点击数据源的测试用例浏览器节点,从快捷菜单选择编辑


然后,您可以在打开的窗口中查看数据源配置,并根据需要进行修改。

打开数据源文件

打开数据源文件的步骤:

  • 右键点击数据源的测试用例浏览器节点,从快捷菜单选择打开数据文件

共享数据源

有关在项目/测试套件级别添加的数据源的信息存储在每个项目内部的 .parasoft 属性文件中。因此,您可以通过源码控制(提交和签出 .parasoft 属性文件)共享有关数据源的信息。

全局数据源——在解决方案级别添加的数据源——也可以通过这种方式共享,但是您需要定义在哪里(例如,在哪个项目中)创建额外的包含全局数据源信息的 .datasource 数据文件。默认情况下,全局数据源信息存储在本地。

为全局数据源指定共享位置的步骤:

  1. 选择 Parasoft> 首选项。将打开一个首选项对话框。
  2. 在左侧窗格中,选择全局数据源
  3. 选择共享单选按钮,并指定要保存 datasources.properties 文件的位置。

确保数据源便携性(便携式模式)

数据源便携模式旨在应对需要将测试套件文件移动到不同位置的特定开发环境。在标准数据源模式下,如果将测试套件文件移动到其他位置,该数据源关联将会丢失。而在便携模式下,您可以轻松将数据源与测试套件一起移动。

为了确保数据源便携性,所有测试套件级别的数据源信息都存储在与测试套件文件名同名且扩展名为 .properties 的文件中。因此,每个测试套件都有自己的数据源设置文件,并且可以与这些数据一起移动。


便携式数据源模式仅适用于在测试套件级别创建的数据源,不适用于在项目或解决方案级别创建的数据源。

更改数据源模式

更改数据源设置的步骤:

  1. 右键点击项目节点,从快捷菜单选择 Parasoft>属性

  2. 展开左窗格中的 Parasoft>C++test> 数据源分类。
  3. 修改使用便携式数据源存储设置,然后点击应用确定按钮。



每次切换模式时,与测试套件关联的所有现有数据源都会自动转换为所选模式。切换到便携模式,数据源设置将从 .parasoft 文件传输到相应的 <test_suite_name>.properties 文件。转换完成后,您会收到消息通知。



您可以通过提交和签出所有或选定的 *.properties 文件,通过源码控制共享有关数据源的信息。

使用 Excel 或 CSV 数据源文件的相对路径

为确保 Excel 和 CSV 数据源类型具有更好的便携性,您可以在 Excel/CSV 文件路径中使用 C++test  ${test_suite_loc} 变量。该变量解析为测试套件文件位置的绝对路径。


配置使用“非托管”数组或 CSV 文件数据源的测试 - 高级

除了使用托管数据源(如上所述,在 C++test 中定义的数据源)之外,您还可以使用未作为托管数据源添加的数组或 CSV 文件中的值。

使用数组数据源值

C++test 中数据源的一种实现方式是基于类型化数组,这些数组随后被单个测试用来逐行遍历数据。

创建可以访问数组数据源的测试用例的步骤:

  • 使用 CPPTEST_TEST_DS(testCaseName, dataSourceCon-fig) 宏注册测试用例。

testCaseName 替换为要访问数据源值的测试用例函数的名称,并将 dataSourceConfig 替换为用于数据源配置的宏。

dataSourceConfig 可使用两个辅助宏:CPPTEST_DS_ARRAY(ARRAY_NAME, ROW, COLUMN)CPPTEST_DS_REPEAT(NUMBER)。

对于 CPPTEST_DS_ARRAY(ARRAY_NAME, ROW, COLUMN),需注意:

  • 此宏使用 ARRAY_NAME 作为数据源。ARRAY_NAME 的类型应为 const char* data[ROW][COLUMN]。
  • 表格中的第一行必须包含列名。
  • 该测试用例将被执行(ROW - 1)次。
  • 数据源访问宏可用于提取值,如以下部分所述。


对于 CPPTEST_DS_REPEAT(NUMBER),需注意:

  • 该测试用例将被执行 NUMBER 次
  • 该测试用例可用于访问自定义数据数组中的值,在用于访问数据源值的宏的 CPPTEST_DS_GET_VALUE 和 CPPTEST_DS_GET_ITERATION 描述中有所说明。

提示

  • 数据源数组可以在测试套件类之外声明(仅适用于 C 测试套件),也可以作为测试套件类成员声明(仅适用于 C++test 测试套件)。请注意,C++test 测试套件可用于 C 语言(假设您有一个 C++ 编译器进行构建)。
  • 当数据源数组被声明为类成员时,访问范围并不重要,因为数组只能由测试用例函数和 setup/teardown 访问,它们都是成员函数。
  • 声明类型化数组并在 setUp 方法中初始化是将数据源数组元素初始化为任意数据的一种十分有效的方法。这些数据可以是动态分配的对象、工厂测试对象等,例如:


#include "cpptest.h" 
int plus_one(int);
class TestSuite_3 : public CppTest_TestSuite {
public:
    CPPTEST_TEST_SUITE(TestSuite_3);
    CPPTEST_TEST_DS(test_ds_repeat, CPPTEST_DS_REPEAT(2));     
    CPPTEST_TEST_SUITE_END();
 
    void setUp();
    void tearDown();
 
    void test_ds_repeat();
private:
    int _dsRepeat_arg[2];
    int _dsRepeat_return[2];
};
CPPTEST_TEST_SUITE_REGISTRATION(TestSuite_3); 
 
void TestSuite_3::setUp()
{
    _dsRepeat_arg[0] = 1;
    _dsRepeat_arg[1] = 2;
}
void TestSuite_3::tearDown()
{
}
void TestSuite_3::test_ds_repeat()
{
    int index = CPPTEST_DS_GET_ITERATION() - 1;
    int _value = _dsRepeat_arg[index];
    int _expected = _dsRepeat_return[index];
 
    int _return = plus_one(_value);
    CPPTEST_ASSERT_INTEGER_EQUAL(_expected, _return);
}

使用非托管 CSV 数据源

除了支持前面章节目录描述的 CSV 数据源之外,当 CSV 数据满足以下条件时,C++test 还可以使用“非托管”CSV 数据源:

  • CSV 数据存储在外部文件中。
  • CSV 数据包含用(可自定义)分隔符分隔的值记录(行)。
  • CSV 数据可以包含表头。
  • CSV 数据值可以包含可选择忽略的空格字符。

有关支持文件类型的更多信息,请参阅 CSV 文件支持详细信息

创建可以访问 CSV 数据源的测试用例的步骤:

  • 使用 CPPTEST_TEST_DS(testCaseName, dataSourceConfig) 宏注册测试用例。

testCaseName 替换为要访问数据源值的测试用例函数的名称,并将 dataSourceConfig 替换为 CPPTEST_DS_CSV(FILE_NAME, SEPARATOR, HAS_HEADER, TRIM)。

CPPTEST_DS_CSV 定义在 C++test 数据源 API 中。其参数为:

  • FILE_NAME - 包含数据源的数据源文件的名称。  可以用完整或相对文件路径指定。
    注意:如果使用相对路径,则相对于测试可执行程序的工作目录,可以在测试配置的测试可执行程序运行目录字段(执行> 运行时选项卡)中自定义。
  • SEPARATOR - 字段分隔符。应指定为字符常量(例如:',')。
  • HAS_HEADER - 如果第一条记录(行)是表头,则应将其设置为 1。否则,应将其设置为 0。
    注意:如果 CSV 文件中没有表头,那么每个列名就是它的序号(从 0 开始)。
  • TRIM - 如果应省略值前/后的空格,则应将其设置为 1。否则,应将其设置为 0。

如果 CSV 文件中没有表头,那么每个字段名就是它的序号(从 0 开始)。值需要使用引号(字符串类型)。例如: CPPTEST_DS_GET_FLOAT("0");

FILE_NAME 可以是完整或相对文件路径。后者是相对于当前目录的路径。

CPPTEST_DS_CSV 示例

CPPTEST_DS_CSV("/home/project/testdata.csv", ',', 1, 0)

  • “/home/project/testdata.csv”将用作数据文件。
  • 用‘,’字符分隔各值。
  • 第一条记录将被视为表头。
  • 值前/后的空格不会被去除。

CPPTEST_DS_CSV("testdata.csv", ';', 0, 1)

  • “testdata.csv”(位于当前工作目录中)将用作数据文件。
  • 用‘;’字符分隔各值。
  • 没有显式表头 - 第一条记录(行)将用作数据。
  • 值前/后的空格将被去除。

CSV 文件支持详细信息

  • 每条记录位于单独一行,由换行符(CRLF)分隔。  例如:
    aaa,bbb,ccc CRLF
    zzz,yyy,xxx CRLF
  • 文件中的最后一条记录可能有也可能没有结束换行符。  例如:
    aaa,bbb,ccc CRLF
    zzz,yyy,xxx
  • 可以有一个可选的表头行,作为文件的第一行出现,其格式与普通记录行相同。  该表头将包含与文件中的字段相对应的名称,并且应包含与文件其余部分中的记录数量相同的字段(表头行存在与否应该通过该 MIME 类型的可选“header”参数来指示)。 
    例如:
    field_name,field_name,field_name CRLF
    aaa,bbb,ccc CRLF
    zzz,yyy,xxx CRLF
  • 在表头和每条记录中,可能有一个或多个字段,用逗号分隔。在整个文件中,每一行应该包含相同数量的字段。  空格视为字段的一部分,不应被忽略。  记录中的最后一个字段后面不能有逗号。  例如:
    aaa,bbb,ccc
  • 每个字段可以选择用双引号括起来(但是有些程序 [如 Microsoft Excel] 则完全不使用双引号)。  如果字段没有用双引号括起来,则字段内不能出现双引号。  例如:
    "aaa","bbb","ccc" CRLF
    zzz,yyy,xxx
  • 包含换行符(CRLF)、双引号和逗号的字段应该用双引号括起来。  示例:
    "aaa","b CRLF
    bb","ccc" CRLF
    zzz,yyy,xxx
  • 如果使用双引号将字段括起来,则字段中出现的双引号必须通过在其前面加上另一个双引号来转义。  例如:
    "aaa","b""bb","ccc"
  • LF(而非 CRLF)可用于分隔记录
  • 值前后的空格可以省略
  • 记录中不需要相同数量的值
  • 非逗号字符可用作字段分隔符

示例
使用 CPPTEST_DS_ARRAY

在本例中,使用了一个数组数据源。首先,定义数据数组:

const char* MyData[][3] = {
    { "arg1",  "arg2", "return" },
    {    "1",	"one",	  "111" },
    {	 "0",   "two",    "222" },
    {    "2", "three",    "333" },
};

它包括三列四行。第一行包含列的名称(arg1arg2return)。另外三行保存测试用例的数据(因此将有三个测试用例执行)。准备好数据后,必须注册测试用例,方法如下:

	CPPTEST_TEST_DS(testFoo2, CPPTEST_DS_ARRAY(MyData, 4, 3));

测试用例 testFoo2 将执行三次,并使用来自 MyData 数组的数据。最后,我们需要编写测试用例。被测函数接受两个参数并返回一个整数。我们将从数据源中获取这两个参数:

    int arg1 = CPPTEST_DS_GET_INTEGER("arg1");     
    const char * arg2 = CPPTEST_DS_GET_CSTR("arg2");

如果具有指定名称的列不可用或其值类型不匹配,测试用例执行将会中止。

对于后置条件检查,我们将从数据源中获取期望的值:

    int expectedReturn = CPPTEST_DS_GET_INTEGER("return");
    /* check return value with value from data source */     
    CPPTEST_ASSERT_INTEGER_EQUAL(expectedReturn, actualReturn);

以下是完成的测试:

class TestWithDataSource : public CppTest_TestSuite 
{
public:
    CPPTEST_TEST_SUITE(TestWithDataSource);
 
    /* register standard test case */     
    CPPTEST_TEST(testFoo1);
 
    /* register test case with "MyData" data source access */     
    CPPTEST_TEST_DS(testFoo2, CPPTEST_DS_ARRAY(MyData, 4, 3));
 
    CPPTEST_TEST_SUITE_END();
...
...
...
 
/* test case using values from data source */
void TestWithDataSource::testFoo2()
{
    /* extract arguments from data source */
    int arg1 = CPPTEST_DS_GET_INTEGER("arg1");
    const char * arg2 = CPPTEST_DS_GET_CSTR("arg2");
 
    /* call tested function */
    int actualReturn = foo(arg1, arg2);
 
    /* extract expected return from data source */
    int expectedReturn = CPPTEST_DS_GET_INTEGER("return");
 
    /* check return value with value from data source */
    CPPTEST_ASSERT_INTEGER_EQUAL(expectedReturn, actualReturn);
}

使用 CPPTEST_DS_REPEAT

在本例中,我们将使用重复数据源:

/* data source for arg1 */
int _arg1[] = {
     1,
     0,
     2,
};
 
/* data source for arg2 */
const char * _arg2[] = {
   "one",    
   "two",
   "three",
};
/* data source for return */
int _return[] = {
   111,
   222,
   333,
};

这是一个特殊的数据源:它不提供对任何数据的访问,只是根据请求次数重复测试用例执行。用户指定在每次运行期间应该使用什么数据。在本例中,我们使用三个独立的数组:_arg1_arg2_return

注册测试用例:

CPPTEST_TEST_DS(testFoo2, CPPTEST_DS_REPEAT(3));

CPPTEST_DS_REPEAT 参数指示测试用例 testFoo2 应该执行几次。

在该测试用例中,我们将直接从数组中获取数据。要从正确的行中获取值,我们可以使用 CPPTEST_DS_GET_ITERATION() 的值作为数组索引,或使用 CPPTEST_DS_GET_VALUE(SOURCE) 宏为执行索引:

    int arg1 = CPPTEST_DS_GET_VALUE(_arg1);
    const char * arg2 = CPPTEST_DS_GET_VALUE(_arg2);

CPPTEST_DS_GET_VALUE 宏中没有范围或类型检查。它只是一个索引(假设数组有正确的索引)。

以下是完成的测试:

class TestWithDataSource : public CppTest_TestSuite 
{
public:
    CPPTEST_TEST_SUITE(TestWithDataSource);
 
    /* register standard test case */
    CPPTEST_TEST(testFoo1);
 
    /* register test case that will be executed number of times */
    CPPTEST_TEST_DS(testFoo2, CPPTEST_DS_REPEAT(3));
 
    CPPTEST_TEST_SUITE_END();
...
...
...
 
/* test case using values from custom arrays */
void TestWithDataSource::testFoo2()
{
    /* extract arguments from data source */
    int arg1 = CPPTEST_DS_GET_VALUE(_arg1);
    const char * arg2 = CPPTEST_DS_GET_VALUE(_arg2);
 
    /* call tested function */
    int actualReturn = foo(arg1, arg2);
 
    /* extract expected return from data source */
    int expectedReturn = CPPTEST_DS_GET_VALUE(_return);
 
    /* check return value with value from data source */
    CPPTEST_ASSERT_INTEGER_EQUAL(expectedReturn, actualReturn);
}

使用 CPPTEST_DS_CSV

下面是存储在 /home/test/t2.data 文件中数据的数据源声明,其中表头和字段用逗号(',')分隔。不会去除空格。

class TestSuite : public CppTest_TestSuite 
{
	public:
	CPPTEST_TEST_SUITE(TestSuite);
	CPPTEST_TEST_DS(test_fooc_1, CPPTEST_DS_CSV("/home/test/t2.data",',', 1, 0));
	CPPTEST_TEST_SUITE_END();
 
	void setUp(); 
	void tearDown();
 
	void test_fooc_1();
};

下面是使用数据源 API 中标准函数的测试用例的定义:

void TestSuite::test_fooc_1()
{
	int _boo  = CPPTEST_DS_GET_INTEGER("first");
        float _goo  = CPPTEST_DS_GET_FLOAT("second");
 
	int _return  = fooc(_boo, _goo, _g);
	CPPTEST_ASSERT_INTEGER_EQUAL(CPPTEST_DS_GET_INTEGER("result"), ( _return ))
}

以下是 CSV 数据源文件(/home/test/t2.data),包含一个表头和三个测试用例。

first,second,result
1,2,3
2,2,4
2,2,5

创建基于数据源的回归测试

为 C++test 随附的 ATM 示例项目(examples 目录中)创建两个基于数据源的回归测试(一个使用字符串数组数据,另一个使用类型化数组数据):

  1. 右键点击项目节点,然后 选择 C++test> 向导 >创建新的测试套件。将打开一个新的测试套件向导。

  2. 将测试套件命名为 TestSuiteAccount(这将是 C++test 套件的类名),将测试套件位置指定为 /ATM/tests/user(如果目录不存在,点击创建目录)。
  3. 测试套件语言字段选择 C++
  4. 不勾选其余选项。
  5. 点击下一步并点击添加按钮两次,为该 Account 类添加两个测试。将其中一个测试命名为 setPasswordTest,另一个命名为 depositTest。完成向导设置将创建一个框架测试套件,并注册了相应测试。
  6. 打开测试套件源文件。
  7. 创建一个用于测试密码设置的字符串数据源数组(如下所示),并将其放在测试套件的源文件中,位于测试套件类声明的上方。通常而言,数据源数组可以遵循标准语言习惯在文件范围内声明,或者作为测试套件类的静态成员声明:

    const char* passwordData [] [2] = {
    	{ "arg1", "result" },
    	{ "", "" },
    	{ "a1", "a1" },
    	{ "really_long_password", "really_long_password" },
    	{ "foo", "goo" }
    };
  8. 为 setPassword 方法编写一个测试用例。该测试应设置密码并检查返回的密码是否符合数据源中指定的密码:

    void TestSuiteAccount::setPasswordTest()
    {
    	const char* password = CPPTEST_DS_GET_CSTR("arg1");
    	const char* result = CPPTEST_DS_GET_CSTR("result");
    	Account _cpptest_object;
    	_cpptest_object.setPassword(password);
    	CPPTEST_ASSERT_CSTR_EQUAL(result, _cpptest_object.getPassword())
    }
  9. #include “Account.hxx” 添加到文件顶部,这样我们就可以获得 Account 类声明。
  10. 按如下方式修改测试套件声明 CPPTEST_TEST(setPasswordTest) 中的测试用例注册信息:

     CPPTEST_TEST_DS(setPasswordTest, CPPTEST_DS_ARRAY(passwordData, 5, 2));
  11. 创建一个自定义测试配置,用于执行用户定义的测试,步骤如下:
    1. 选择 Parasoft> 测试配置
    2. 右键点击内建> Run Unit Tests,然后选择复制
    3. 将新的用户定义测试配置重命名为“Run DS  Tests”。
    4. 打开执行> 常规选项卡。
    5. 将测试套件定位模式更改为仅包括 /tests/user/* 中的测试。
    6. 点击应用,然后确认保存更改。
  12. 选择项目节点,然后运行新的“Run DS Tests”测试配置。
  13. 测试完成后,打开质量任务视图。在修复单元测试分类中,您将看到一个指向数据源第 4 行的单元测试断言,其中包含有意未匹配的数据(模拟回归失败),以及来自第二个测试用例的另一个断言。
  14. 使用类型化数组中的数据创建第二个测试用例。创建一个包含 deposit 值的 double 类型数据源数组,以及另一个包含期望的帐户 balance 值的数据源数组。这一次,我们让数组成为测试套件的成员。测试套件声明的结尾应类似于下面的示例:

     		void depositTest();
    	private:
    		static double deposit []; 
    		static double balance [];
    };
    		double TestSuiteAccount::deposit [] = {
    			0.0,
    			1.0,
    			-2.0,
    			1e06
    		};
    		double TestSuiteAccount::balance [] = {
    			1.0,
    			2.0,
    			-1.0,
    			1000001.0
    };
  15. 为 deposit 函数编写一个测试,并检查最终 balance 以进行回归:

    void TestSuiteAccount::depositTest()
    {
    	double dep_value = CPPTEST_DS_GET_VALUE(deposit);
    	double balance_value = CPPTEST_DS_GET_VALUE(balance); 
    	Account _cpptest_object(1.0);  // create account with initial deposit
    	_cpptest_object.deposit(dep_value); // additional deposit
    	CPPTEST_ASSERT_DOUBLES_EQUAL(balance_value, _cpptest_object.getBal-ance(), 1e-6)
    }
  16. 将测试 CPPTEST_TEST(depositTest) 的注册信息更改为运行 4 次:

        CPPTEST_TEST_DS(depositTest, CPPTEST_DS_REPEAT(4));
  17. 对项目重新运行“Run DS Tests”测试配置。
  18. 查看质量任务视图的修复单元测试分类下报告的结果。由于新测试中的所有值都匹配,因此不会报告其他任务。