桩函数 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; }