桩函数 API 为简单类型值提供开箱即用的支持。高级用户可以扩展桩函数 API 以建立对选定复杂类型的专用支持。此过程在使用复杂类型的高级方法中进行了描述。然而,在许多情况下,使用复杂类型的基本方法,与桩函数主体的 helper 命名参数一起使用,就足够了。下面给出了这种方法的一个示例。
处理复杂类型的基本方法
考虑以下结构定义:
struct Point { int _x; int _y;
};
桩函数是为以下函数声明创建的:
Point movePoint(Point line, int xoff, int yoff);
如果需要修改函数返回值,则必须对存根主体进行以下修改:
- 应该为每个要修改的成员引入 Helper 变量
- 变量应该公开以供外部修改(通过测试用例代码)
- 修改后的值应重新分配回原始返回值
Point CppTest_Stub_movePoint (Point point)
{
Point __return = Point();
int __callOrig = 0;
int __point_x = __return._x; /* [1] helper variable for complex type member */
int __point_y = __return._y; /* [1] helper variable for complex type member */
CPPTEST_ACTUAL_CALL("movePoint").WithArg("point", &point).
WithArg("__return", &__return)).WithArg("__callOrig", ByRef(__callOrig)).
/* [2] expose variable for external modification */
WithArg("__point_x", ByRef(__point_x)).
/* [b] expose variable for external modification */
WithArg("__point_y", ByRef(__point_y)).
End();
__return._x = __point_x; /* [3] update return value with modified value */
__return._y = __point_y; /* [3] update return value with modified value */
if (__callOrig) {
Point __return = movePoint(point);
CPPTEST_ACTUAL_AFTER_CALL("movePoint").
WithArg("point", &point).WithArg("__return", &__return)).
WithArg("__callOrig", ByRef(__callOrig)).End();
return __return;
}
return __return;
}
然后,在测试用例内部可以修改返回值,如下所示:
CPPTEST_ON_CALL("movePoint").Arg("__point_x").Assign(1).Arg("__point_y").Assign(2);
处理复杂类型的高级方法
将复杂类型与桩函数 API 一起使用需要编写额外的特定于类型的 helper 程序代码,以便于访问复杂类型的数据成员。提供此附加类型特定实用程序代码后,您可以使用基本桩函数 API 中的函数访问复杂类型字段。
为了说明这个概念,假设以下结构定义:
struct Point { int _x; int _y;};struct Line { Point _p1; Point _p2;};
桩函数是为以下函数声明创建的:
Line moveLine(Line line, int xoff, int yoff);
在此示例中,目标是按照以下构造为复杂类型参数和参数启用桩函数行为配置:
CPPTEST_ON_CALL("moveLine").Arg("__return").Field("_p1").Field("_x").Assign(0); CPPTEST_ON_CALL("moveLine").Arg("__line").Field("_p2").Field("_y").Assign(12);
为了实现上述目标,必须将以下代码添加到定义 moveLine() 函数桩函数的源文件中。
/**
* Field access function for Point structure
* /
tgr_value CppTest_Tgr_GetField_Point(tgr_value_ptr obj, tgr_value_ptr field_name)
{
Point *point = (Point *)obj->value.ptr;
const char* name = tgr_value_get_string(field_name);
if (tgr_strcmp(name, "_x") == 0) {
return tgr_int_ref(&point->_x);
} else if (tgr_strcmp(name, "_y") == 0) {
return tgr_int_ref(&point->_y);
} else {
return tgr_error(c_tgr_error_wrong_get_field_argument);
}
}
/**
* Helper function returning pointer to structure with Point type
* specific utilities
*/
tgr_type_ptr CppTest_Tgr_Type_Data(void)
{
static struct tgr_class_definition class_definition = {tgr_false};
if (!class_definition.initialized) {
tgr_initialize_class_definition(&class_definition);
class_definition.vtbl.get_field = CppTest_Tgr_GetField_Data;
}
return &class_definition.type;
}
/**
* Field access function for Line structure
*/
tgr_value TRIGGER_CDECL CppTest_Tgr_GetField_Line(tgr_value_ptr obj,
tgr_value_ptr field_name)
{
Line *line = (Line *)obj->value.ptr;
const char* name = tgr_value_get_string(field_name);
if (tgr_strcmp(name, "_p1") == 0) {
return tgr_object(&line->p1, CppTest_Tgr_Type_Point());
} else if (tgr_strcmp(name, "_p2") == 0) {
return tgr_object(&line->_p2, CppTest_Tgr_Type_Point());
} else {
return tgr_error(c_tgr_error_wrong_get_field_argument);
}
}
/**
* Helper function returning pointer to structure with Line type
* specific utilities
*/
tgr_type_ptr CppTest_Tgr_Type_Line(void)
{
static struct tgr_class_definition class_definition = {tgr_false};
if (!class_definition.initialized) {
tgr_initialize_class_definition(&class_definition);
class_definition.vtbl.get_field = CppTest_Tgr_GetField_Line;
}
return &class_definition.type;
}
最后,需要在桩函数主体中安装特定于类型的操作代码。这需要修改自动生成的桩函数主体并将以下方法调用替换为新调用:
WithArg(const char* name, RValue value)
替换调用:
WithArg(const char* name, const volatile void* obj, tgr_type_ptr type)
方法调用允许您指定专用类型实用程序。修改后的桩函数主体应类似于以下示例:
Line CppTest_Stub_moveLine (Line line, int xoff, int yoff)
{
Line __return = Line();
int __callOrig = 0;
CPPTEST_ACTUAL_CALL("moveLine ").
WithArg("line", &line, CppTest_Tgr_Type_Line()).
WithArg("xoff", ByRef(xoff)).
WithArg("xoff", ByRef(yoff)).
WithArg("__return", &__return, CppTest_Tgr_Type_Line()).
WithArg("__callOrig", ByRef(__callOrig)).End();
if (__callOrig) {
Line __return = moveLine(line, xoff, yoff);
CPPTEST_ACTUAL_AFTER_CALL("moveLine ").
WithArg("line", &line, CppTest_Tgr_Type_Line()).
WithArg("xoff", ByRef(xoff)).
WithArg("xoff", ByRef(yoff)).
WithArg("__return", &__return, CppTest_Tgr_Type_Line()).
WithArg("__callOrig", ByRef(__callOrig)).End();
return __return;
}
return __return;
}