本主题说明如何在测试期间使用预定义或自动生成的数据源值。针对不同数据集运行测试能够让您轻松增加测试量和覆盖率。
章节目录:
在桩函数中使用数据源
您配置的在 C++test 中使用的任何数据源都可以在桩函数中使用。详细信息请参阅在桩函数中使用数据源。
添加数据源
可以使用 GUI 向导在 C++test 中定义数据源。在向导中,通过逗号分隔值文件(.csv)、Excel 电子表格(.xls)、数据库查询或 C++test 管理的数据源表指定数据源。在测试用例执行过程中,测试用例会使用从特定数据源收集的值。
托管数据源可以通过测试用例浏览器在项目级别(对所有项目测试套件可见)或在单个测试套件级别(仅由特定的测试套件使用)定义。此外,还可以在工作空间级别创建托管数据源)。
在项目/测试套件级别添加已有数据源
在项目/测试套件级别创建托管数据源的步骤:
- 在测试用例浏览器中选择项目或测试用例节点。
- 右键点击选择的节点,然后从快捷菜单中选择新建> 数据源。
指定数据源类型。
配置数据源 (例如,指定 .csv 文件的路径,或数据库参数和 SQL 查询)。
指定 JDBC 驱动程序
连接到数据库需要 JDBC 驱动程序。您可以通过首选项面板的 JDBC 驱动程序页面添加驱动程序(Parasoft> 首选项> JDBC 驱动程序)。
在工作空间级别添加已有数据源
在 工作空间 级别创建托管数据源的步骤:
- 右键点击测试用例浏览器视图中的全局数据源节点,然后选择新建> 数据源。
- 定义新的托管数据源。
自动生成新的数据源
C++test 可以生成逗号分隔值文件(.csv)或包含自动生成的数据源值的 C++test 管理表数据源。
有关在测试用例编辑器中自动生成新数据源的信息,请参阅使用数据源参数化在测试用例编辑器中添加的测试用例。
如果在测试用例向导中配置测试用例:
- 点击测试用例向导编辑器页面的自动生成按钮。
- 在打开的自动生成窗口中指定所需的设置。
生成数据源时,C++test 为每个具有可编辑值(布尔、整数、浮点和字符串类型)的前置和后置条件创建一个单独的列。该数据源在测试套件级别生成。
生成后,生成的数据源就可以用于参数化测试套件中的其他测试用例。
使用数据源值参数化测试用例
使用数据源参数化在测试用例编辑器中添加的测试用例
您可以使用数据源值来参数化通过测试用例编辑器创建的测试用例(请参阅使用测试用例编辑器添加测试套件和测试用例)。这些值可以在内置到测试用例中的数据源表中提供,也可以在外部数据源中提供。
- 打开测试用例浏览器视图,右键点击测试套件
- 选择新建> 使用测试用例编辑器…
- 从创建下面的测试用例下拉列表选择一个函数。
- 点击创建新的参数化测试用例按钮(
- 选择要使用的数据源。以下选项可用:
内置的表 - 向测试用例添加一个指定参数化值的表(有关参数 API 的详细信息,请参阅添加测试用例参数化值,您可以用来访问内置表中指定的值)。
外部数据源 - 自动生成用于指定参数化值的外部数据源:逗号分隔值文件(.csv)或表格数据源。 如果选择此选项,应在打开的自动生成窗户中指定所需的设置并点击确定。该数据源在测试套件级别生成。
- 保存测试用例,将其添加到测试套件中。
使用数据源参数化在测试用例向导中编写的测试用例
您可以使用数据源值来参数化已有的(自动生成的或用户定义的)测试用例,以及在测试用例向导中编写测试用例时定义测试用例值。数据源值可以取自上文描述的 C++test 中定义的任何数据源。
注意
C++test 无法自动验证由数据源值参数化的测试用例执行产生的未验证的结果和失败的断言。这是因为它通常也要求使用通过数据源参数化的期望结果。
通过测试用例向导配置数据源使用
使用测试用例向导添加从先前定义的托管数据源中提取值的新测试用例:
- 在测试用例浏览器中,右键点击测试套件节点,然后从快捷菜单中选择新建> 使用测试用例向导。
- 在第一个页面中,指定源文件(编译单元)和要为其添加测试用例的函数,然后输入测试用例的名称。
- 点击下一步打开下一个向导页。
- 勾选使用数据源复选框,选择相应数据源。
- 使用 GUI 控件指定测试用例的输入和期望的输出值来配置测试用例。
- 要将数据源值用于特定的前置或后置条件,可双击相关节点,然后选择相应的数据源列名。数据源值以花括号括起来的列名形式在组合框中列出,例如“{myColumnName}”。
- 点击完成生成测试用例。新的测试用例将添加到测试套件中,生成的源代码将在编辑器中打开。
通过测试用例代码配置数据源使用
使用先前定义的托管数据源参数化已有(自动生成或用户定义)测试用例:
- 指定要与注册宏一起使用的数据源
CPPTEST_TEST_DS(<TEST_CASE_NAME>,
CPPTEST_DS("<MANAGED_DATA_SOURCE_NAME>")); - 指定如何将数据源值与 CPPTEST_DS* 宏一起使用(在用于访问数据源值的宏中有所说明)。
示例
例如,要使用 Excel 工作表中的值参数化已有测试用例,我们之后将该工作表称为“MyDataSourceForSum”:
- 打开项目。
- 确保已将 Excel 工作表添加为托管数据源:
- 在测试用例浏览器中,右键点击项目节点,从快捷菜单中选择新建> 数据源。
- 选择 Excel,然后点击完成。
- 为数据源输入一个有意义的名称(例如“MyDataSourceForSum”)。
- 输入您的 .xsl 文件的位置。
- (可选)点击显示列并快速验证列名。
- 点击确定。新的数据源将显示在测试用例浏览器中。
- 在测试用例浏览器中,双击您要参数化的测试用例。
找到测试用例注册行(在测试套件文件中)。例如:
... CPPTEST_TEST(sumTest1); ...
将注册类型更改为使用数据源(your_Data_Source_name):
... CPPTEST_TEST_DS(sumTest1, CPPTEST_DS("MyDataSourceForSum")); ...
- 进入测试用例定义并添加代码,告诉 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 结尾的字符串值 |
| N/A |
返回一个字符值 |
| N/A |
返回一个整数值 |
| 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> 是枚举的全名,包括所有命名空间名称。例如: 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:
如果为 false:
|
有符号整数 | CPPTEST_DS_GET_INTEGER() | 整数的十进制表示法(可以使用- 或 + 号作为前缀);例如:
前缀为 0x 或 0X 的整数十六进制表示法(可以使用- 或 + 号作为前缀);例如:
前缀为 0 的整数八进制表示法(可以使用- 或 + 号作为前缀);例如:
前缀为 0b 或 0B 的整数二进制表示法(可以使用- 或 + 号作为前缀);例如:
|
无符号整数 | CPPTEST_DS_GET_UINTEGER() | 整数的十进制表示法;例如:
前缀为 0x 或 0X 的整数十六进制表示法;例如:
前缀为 0 的整数八进制表示法;例如:
前缀为 0b 或 0B 的整数二进制表示法;例如:
|
浮点 | CPPTEST_DS_GET_FLOAT() | 浮点值的实际格式取决于所使用的编译器的配置——CPPTEST_STR_TO_FLOAT / CPPTEST_SCANF_FLOAT / 此外,后面也可以跟一个十进制指数。十进制指数由“E”或“e”组成,后跟可选的加号或减号,然后是一串非空的十进制数字,表示乘以 10 的幂。 示例:
|
char | CPPTEST_DS_GET_CHAR() | 使用的字符;例如:
此外,应使用以下类似 C 语言风格的转义序列来处理特殊字符:
对于不可打印的字符,可以使用字符的八进制(1-3 个前缀为 \ 的数字)或十六进制(1-2 个前缀为 \x 的数字)表示法;例如:
|
string | CPPTEST_DS_GET_CSTR() | 要使用的字符串;例如:
此外,应使用以下类似 C 语言风格的转义序列来处理特殊字符:
示例:
要在字符串中使用不可打印的字符,可以使用字符的八进制(1-3 个前缀为 \ 的数字)或十六进制(1-2 个前缀为 \x 的数字)表示法;例如:
为了将空值定义为数据源中的 C 字符串值,可以配置托管数据源识别一些字符;例如 $ 作为特殊值前缀,可以在数据源中使用带有该前缀字符的 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() | 数据源值可以用引号括起来(可以在数据源配置中定义引号);例如:
这对于需要在值中使用分隔符或者引号本身的情况而言是必需的。针对后面一种情况,需要将用作数据源值中元素的引号重复使用;例如:
|
Excel 电子表格(托管数据源) | CPPTEST_DS() | 不需要进行特定的 Excel 值准备。注意,需要格式化数据以用于上述特定类型。 为了确保 C++test 正确处理值,您可以对电子表格中的所有单元格使用文本格式。例如,通过这种方式,您可以确保整数值的八进制表示形式被正确处理。 |
表格(托管数据源) | CPPTEST_DS() | 不需要进行特定的表格值准备。注意,需要格式化数据以用于上述特定类型。 |
CSV file | CPPTEST_DS_CSV() | 数据源值可以用引号括起来(可以在数据源配置中定义引号);例如:
这对于需要在值中使用分隔符或者引号本身的情况而言是必需的。针对后面一种情况,需要将用作数据源值中元素的引号重复使用;例如:
|
源代码数组 | CPPTEST_DS_ARRA Y() | 不需要进行数组特定的值准备。注意,需要格式化数据以用于上述特定类型。 |
数据库(托管数据源) | CPPTEST_DS() | 不需要进行特定的数据源值准备。注意,需要格式化数据以用于上述特定类型。 |
探索可用的数据源
查看/修改数据源配置
查看或编辑现有数据源配置的步骤:
- 右键点击数据源的测试用例浏览器节点,从快捷菜单选择编辑。
然后,您可以在打开的窗口中查看数据源配置,并根据需要进行修改。
打开数据源文件
打开数据源文件的步骤:
- 右键点击数据源的测试用例浏览器节点,从快捷菜单选择打开数据文件。
共享数据源
有关在项目/测试套件级别添加的数据源的信息存储在每个项目内部的 .parasoft 属性文件中。因此,您可以通过源码控制(提交和签出 .parasoft 属性文件)共享有关数据源的信息。
全局数据源——在工作空间级别添加的数据源——也可以通过这种方式共享,但是您需要定义在哪里(例如,在哪个项目中)创建额外的包含全局数据源信息的 .datasource 数据文件。默认情况下,全局数据源信息存储在本地。
为全局数据源指定共享位置的步骤:
- 选择 Parasoft> 首选项。将打开一个首选项对话框。
- 在左侧窗格中,选择全局数据源。
- 选择共享单选按钮,并指定要保存 datasources.properties 文件的位置。
确保数据源便携性(便携式模式)
数据源便携模式旨在应对需要将测试套件文件移动到不同位置的特定开发环境。在标准数据源模式下,如果将测试套件文件移动到其他位置,该数据源关联将会丢失。而在便携模式下,您可以轻松将数据源与测试套件一起移动。
为了确保数据源便携性,所有测试套件级别的数据源信息都存储在与测试套件文件名同名且扩展名为 .properties 的文件中。因此,每个测试套件都有自己的数据源设置文件,并且可以与这些数据一起移动。
便携式数据源模式仅适用于在测试套件级别创建的数据源,不适用于在项目或工作空间级别创建的数据源。
更改数据源模式
更改数据源设置的步骤:
右键点击项目节点,从快捷菜单选择 属性。
- 展开左窗格中的 Parasoft>C++test> 数据源分类。
- 修改使用便携式数据源存储设置,然后点击应用或确定按钮。
每次切换模式时,与测试套件关联的所有现有数据源都会自动转换为所选模式。切换到便携模式,数据源设置将从 .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" }, };
它包括三列四行。第一行包含列的名称(arg1
、arg2
和 return
)。另外三行保存测试用例的数据(因此将有三个测试用例执行)。准备好数据后,必须注册测试用例,方法如下:
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 目录中)创建两个基于数据源的回归测试(一个使用字符串数组数据,另一个使用类型化数组数据):
右键点击项目节点,然后 选择新建> 其他,选择 C++test> 测试套件,然后点击下一步。将打开一个新的测试套件向导。
- 将测试套件命名为
TestSuiteAccount
(这将是 C++test 套件的类名),将测试套件位置指定为/ATM/tests/user
(如果目录不存在,点击创建目录)。 - 在测试套件语言字段选择 C++。
- 不勾选其余选项。
- 点击下一步并点击添加按钮两次,为该 Account 类添加两个测试。将其中一个测试命名为
setPasswordTest
,另一个命名为depositTest
。完成向导设置将创建一个框架测试套件,并注册了相应测试。 - 打开测试套件源文件。
创建一个用于测试密码设置的字符串数据源数组(如下所示),并将其放在测试套件的源文件中,位于测试套件类声明的上方。通常而言,数据源数组可以遵循标准语言习惯在文件范围内声明,或者作为测试套件类的静态成员声明:
const char* passwordData [] [2] = { { "arg1", "result" }, { "", "" }, { "a1", "a1" }, { "really_long_password", "really_long_password" }, { "foo", "goo" } };
为 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()) }
- 将
#include “Account.hxx”
添加到文件顶部,这样我们就可以获得 Account 类声明。 按如下方式修改测试套件声明
CPPTEST_TEST(setPasswordTest)
中的测试用例注册信息:CPPTEST_TEST_DS(setPasswordTest, CPPTEST_DS_ARRAY(passwordData, 5, 2));
- 创建一个自定义测试配置,用于执行用户定义的测试,步骤如下:
- 选择 Parasoft> 测试配置。
- 右键点击内建> Run Unit Tests,然后选择复制。
- 将新的用户定义测试配置重命名为“Run DS Tests”。
- 打开执行> 常规选项卡。
- 将测试套件定位模式更改为仅包括
/tests/user/*
中的测试。 - 点击应用,然后确认保存更改。
- 选择项目节点,然后运行新的“Run DS Tests”测试配置。
- 测试完成后,打开质量任务视图。在修复单元测试分类中,您将看到一个指向数据源第 4 行的单元测试断言,其中包含有意未匹配的数据(模拟回归失败),以及来自第二个测试用例的另一个断言。
使用类型化数组中的数据创建第二个测试用例。创建一个包含 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 };
为 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) }
将测试 CPPTEST_TEST(depositTest) 的注册信息更改为运行 4 次:
CPPTEST_TEST_DS(depositTest, CPPTEST_DS_REPEAT(4));
- 对项目重新运行“Run DS Tests”测试配置。
- 查看质量任务视图的修复单元测试分类下报告的结果。由于新测试中的所有值都匹配,因此不会报告其他任务。