本主题说明测试期间如何使用预定义或自动生成的数据源值。 在不同的数据集上运行测试的能力使您可以轻松地增加测试量和覆盖范围。
内容包括:
在 stub 中使用数据源 您配置用于C ++ test的任何数据源都可以在 stubs 数据库中使用。有关详细信息,请参阅 在 Stubs 中使用数据源。 |
可以使用 GUI 向导在 C++test 中定义数据源。该向导允许您从逗号分隔的值文件(.csv),Excel 电子表格(.xls)中指定数据源,或 C++test 托管数据源表。在测试用例执行过程中,测试用例使用从给定数据源收集的值。
可以从【测试用例浏览器】在项目级别(对于所有项目测试套件可见)或在单个测试套件级别(仅由给定测试套件使用)定义托管数据源。此外,可以在以下位置创建托管数据源:解决方案级别)。
要在项目/测试套件级别创建托管数据源:
指定数据源类型。
配置数据源
使用 NULL 引用而不是 NULL 字符串 要使用 NULL 引用而不是 NULL 字符串,请从特殊值前缀 字段中选择 $ , 然后在 CSV 文件输入 NULL 之前使用 $ 前缀; 例如: |
在以下位置创建托管数据源 解决方案 级别:
C++test 可以使用自动生成的数据源值来生成逗号分隔值文件(.csv) 或 C++test 托管数据源表。
有关在【测试用例编辑器】中自动生成新数据源的信息,请参阅 使用数据源对在【测试用例编辑器】中添加的测试用例进行参数化。。
如果正在【测试用例向导】中配置测试用例:
生成数据源时,C++test 为每个具有可编辑值(布尔、整数、浮点和字符串类型)的前置条件和后置条件创建一个单独的列。数据源在测试套件级别生成。
一旦生成,就可以使用生成的数据源对测试套件中的其他测试用例进行参数化。
您可以使用数据源值来参数化使用测试用例编辑器创建的测试用例(请参见 使用测试用例编辑器添加测试套件和测试用例)。可以在内置于测试用例的数据源表中或在外部数据源中提供这些值。
您可以使用数据源值来参数化现有的(自动生成的或用户定义的)测试用例,以及在【测试用例向导】中编写测试用例时定义测试用例的值。如上所述,可以从 C++test 中定义的任何数据源获取数据源值。
C++test 无法自动验证由于执行了用数据源值参数化的测试用例而导致的未验证结果和失败的断言。这是因为它通常需要使用预期结果,该预期结果也已与数据源一起参数化。 |
要使用测试用例向导来添加新的测试用例,用从先前定义的托管数据源中提取值:
要使用先前定义的托管数据源对现有(自动生成或用户定义的)测试用例进行参数化:
例如,要使用 Excel 工作表中的值来参数化现有测试用例,我们将其称为"MyDataSourceForSum":
查找测试用例注册行(在测试套件文件中)。示例
... CPPTEST_TEST(sumTest1); ... |
更改注册类型以使用数据源(your_Data_Source_name):
... CPPTEST_TEST_DS(sumTest1, CPPTEST_DS("MyDataSourceForSum")); ... |
... /* 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 */ ... |
执行测试用例时,将使用 Excel 类型的 "MyDataSourceForSum” 数据源中的值对其进行参数化。
以下宏可用于访问数据源中的值。每个宏都使用参数 NAME,该参数为数据源列指定唯一的标识符。
为了这样... | 使用此宏... | 注意 |
---|---|---|
返回以空值终止的字符串值 |
| 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 不为 null,则缓冲区的大小将存储在此处。 |
返回一个枚举值 |
| <范围枚举名称> 是枚举的全名,包括所有命名空间名称。示例INNER_NS::MyEnumeration, INNER_NS::MyClass::MyEnumeration |
从 SOURCE 数组返回一个值 | CPPTEST_DS_GET_VALUE(SOURCE) | 应该将数组类型的变量指定为 SOURCE 参数: 在每个后续测试用例执行之后,从中提取值的行数将自动增加。 |
返回当前迭代(行号) | unsigned int CPPTEST_DS_GET_ITERATION( ) | 可用于确定当前的迭代/行数。 |
如果当前数据源的当前迭代中存在“名称”列,则返回非零值。 | int CPPTEST_DS_HAS_COLUMN(const char* name) | 可以在 stubs 用于指定测试用例的行为 (详情参见 Using Data Sources in Stubs )。如果不使用数据源,则返回零。 |
下表提供了关于指定类型的数据源值的受支持格式信息:
数据源类型 | 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 的幂。 示例:
| |
字符 | CPPTEST_DS_GET_CHAR() | 要使用的字符; 例如。
此外,应使用以下类似C的转义序列来处理特殊字符:
对于不可打印的字符,可以使用该字符的八进制(以 \ 开头的1-3位数字)或十六进制(以 \x 开头的1-2位数字)表示。 例如。
| |
字符串 | CPPTEST_DS_GET_CSTR() | 要使用的字符串; 例如。
此外,应使用以下类似C的转义序列来处理特殊字符:
示例
对于不可打印的字符字符串,可以使用该字符的八进制(以\开头的1-3位数字)或十六进制(以 \x 开头的1-2位数字)表示。 例如。
要将 null 定义为数据源中的 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 文件 | CPPTEST_DS_CSV() | 数据源值可能用引号引起来(引号可以在数据源配置中定义); 例如。:
如果需要在值中使用分隔符或在值中使用引号本身,则这是必需的。在后一种情况下,用作数据源值元素的引号需要加倍; 例如。:
|
源代码数组 | CPPTEST_DS_ARRA Y() | 无需准备数组特定的值。注意数据需要如上所述格式化以用于特定类型。 |
要查看或编辑现有数据源的配置,请执行以下操作:
然后,您可以在打开的窗口中查看数据源配置,并根据需要对其进行修改。
要打开数据源文件,请执行以下操作:
有关在项目/测试套件级别添加的数据源的信息存储在每个项目内的 .parasoft 属性文件中。因此,您可以通过源代码控制(通过提交和检出 .parasoft 属性文件)共享有关数据源的信息。
全局数据源-在以下位置添加的数据源解决方案级别-也可以通过这种方式共享,但是您需要定义在何处(例如,在哪个项目内)来创建其他 .datasource 数据文件,其中包含有关全局数据源的信息。默认情况下,全局数据源信息存储在本地。
为全局数据源指定共享位置:
数据源可移植模式旨在处理需要将测试套件文件移动到不同位置的特定开发环境。在标准数据源模式下,如果将测试套件文件移动到其他位置,则该数据源关联将丢失。在便携模式下,您可以轻松地将数据源与测试套件一起移动。
为了确保数据源的可移植性,所有测试套件级别的数据源信息都存储在一个文件中,该文件的名称与测试套件文件的名称相同,并且扩展名为 .properties。因此,每个测试套件都有其自己的数据源设置文件,并且可以与这些数据一起移动。
便携式数据源模式仅适用于在测试套件级别创建的数据源-不适用于项目或解决方案级别。
要改数据源模式,请执行以下操作:
右键单击项目节点,然后选择 Parasoft>来自快捷菜单中的属性 。
每次切换模式时,与测试套件关联的所有现有数据源都会自动转换为所选模式。切换到便携模式会使数据源设置从 .parasoft 文件传输到相应的 <test_suite_name>.properties 文件。转换完成时,将会有一条消息通知您。
您可以通过提交并检出所有或选定的 *.properties 文件,通过源代码控制共享有关数据源的信息。
为了确保更好地移植 Excel 和 CSV 数据源类型,可以在 Excel / CSV 文件路径中使用 C++test ${test_suite_loc} 变量。此变量解析为测试套件文件位置的绝对路径。
除了使用托管数据源(如上所述,在 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)
, 注意:
const char* data[ROW][COLUMN].
用 CPPTEST_DS_REPEAT(NUMBER)
, 注意:
提示
#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 数据满足以下条件时,C++test 还可以使用“非托管” CSV 数据源:
有关支持的文件类型的更多信息,请参见 CSV File Support Details。
要创建一个可以访问 CSV 数组数据源的测试用例:
CPPTEST_TEST_DS(testCaseName, dataSourceConfig)
宏注册测试用例。将 testCaseName
替换为要访问数据源值的测试用例函数的名称,并将dataSourceConfig
替换为 CPPTEST_DS_CSV(FILE_NAME, SEPARATOR, HAS_HEADER, TRIM)。
CPPTEST_DS_CSV 在 C++test 数据源 API 中定义。它的参数是:
如果 CSV 文件中没有标题,则每个字段名称都是其序号(以 0 开头)。值应加引号(字符串类型)。示例:CPPTEST_DS_GET_FLOAT("0");
可以使用完整或相对文件路径指定它。FILE_NAME 可以是完整或相对文件路径。
CPPTEST_DS_CSV("/home/project/testdata.csv", ',', 1, 0)
CPPTEST_DS_CSV("testdata.csv", ';', 0, 1)
在此示例中,使用了数组数据源。首先,我们定义数据数组:
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
将执行3次,并将从 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); } |
在此示例中,我们将使用重复数据源:
/* 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
, and _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); } |
这是存储在文件 /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> Wizards> Create New Test Suite。这将打开一个新的测试套件向导。
TestSuiteAccount
作为测试套件名称(这将是C ++测试套件的类名称) 并指定 /ATM/tests/user
作为测试套件的位置 (如果目录不存在,请单击 创建目录y )。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)); |
/tests/user/*
中的测试。使用类型化数组中的数据创建第二个测试用例。创建一个类型为 double 的带有存款值的数据源数组,并创建另一个类型的具有预期账户余额的值。这次,让我们成为测试套件的数组成员。测试套件声明的结尾应如下所示:
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 }; |
为存款函数编写测试,并检查最终余额以进行回归:
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)); |