本主题说明如何使用桩函数回调进行动态桩函数配置。

此章节:

说明

桩函数回调为编程指定于测试用例的桩函数逻辑提供了强大的机制。对于每个测试用例,您可以定义在测试用例执行期间每次调用桩函数时要执行的特定桩函数行为。C++test 自动生成运行特定于测试用例的桩函数逻辑的代码,因此您无需修改​​主桩函数定义。

您可以通过以下方式之一配置桩函数回调:

如果未定义特定于测试用例的桩函数逻辑怎么办?

每个 C/C++test 的桩函数都将其默认逻辑内置到桩函数定义中-通常,桩函数仅返回简单/默认返回值。如果桩函数未定义桩函数回调函数,则调用桩函数时 C++test 将使用默认逻辑。另外,如果未定义测试专用的桩函数逻辑,则可以配置 C/C++test 调用原始函数,请参见创建调用原始函数的桩函数

快速开启使用桩函数回调

在创建桩函数之前,请确保在【桩函数】视图中启用启用桩函数回调 选项(请参见【桩函数】视图中的【配置桩函数】选项) 或在测试配置中 (参见 执行选项卡设置-定义测试的执行方式) 。

在测试用例编辑器中配置桩函数行为

  1. 使用 生成自动桩函数创建用户桩函数 选项为您要配置的功能创建桩函数(请参见 添加和修改桩函数)。
  2. 在【测试用例编辑器】中打开测试用例。
  3. 添加一个新的 桩函数配置步骤,并指定您要配置的 函数
  4. 使用可用的操作和输入/输出参数定义桩函数逻辑。
  5. 执行您的测试用例。运行测试用例时,将在调用桩函数时执行在桩函数配置步骤中定义的自定义桩函数逻辑。

有关使用【测试用例编辑器】配置桩函数行为的更多详细信息,请参见 使用【测试用例编辑器】添加测试套件和测试用例-配置桩函数行为

在源代码中配置桩函数行为

  1. 使用 生成自动桩函数创建用户桩函数 选项为您要配置的功能创建桩函数(请参见 添加和修改桩函数)。

  2. 在代码编辑器中打开测试套件文件。
  3. 将桩函数回调函数添加到测试套件文件。

  4. 使用可用的输入/输出参数在桩函数回调函数中定义桩函数逻辑。

    (tick) 您可以从桩函数文件复制桩函数回调签名。请参见Stub Callback Execution

    (tick) 如果需要,您可以修改桩函数回调函数的名称。

  5. 导航到测试用例定义,并使用以下宏注册桩函数回调:
    CPPTEST_REGISTER_STUB_CALLBACK(<STUB_ID>, &<STUB_CALLBACK_NAME>)

    (tick) 您可以从桩函数文件中复制桩函数标识符<STUB_ID>请参见 Stub Callback Execution

    在调用被测函数之前,请确保已注册回调。

  6. 执行您的测试用例。执行测试用例时,将在调用桩函数时执行您配置的桩函数逻辑。

请参见Stub Callback Details有关桩函数回调功能和桩函数回调注册的更多信息。

桩函数回调详细信息

桩函数回调框架包含以下组件:

  • 桩函数回调函数:用户定义的函数,用于实现各个桩函数的自定义桩函数逻辑。
  • 桩函数回调注册:一种激活桩函数回调功能的机制,该功能通常放置在测试用例中。
  • 桩函数回调执行:桩函数回调函数的调用,该函数内置在 C++test 的桩函数定义中。

桩函数回调函数

桩函数回调函数是用户定义的 C/C++ 函数,其中包含要在调用相关桩函数时执行的逻辑。它具有从桩函数/桩函数函数的签名派生的唯一签名:

void <CALLBACK_NAME>(CppTest_StubCallInfo* stubCallInfo, <STUB_IN_OUT_PARAMETERS>)

桩函数回调函数的接口包括桩函数函数的所有输入/输出参数(<STUB_IN_OUT_PARAMETERS>),以及其他帮助程序参数(stubCallInfo)。您还可以自定义桩函数回调函数的名称 (<CALLBACK_NAME>)。

以下示例演示了如何为int processValues(int i, int j);自定义桩函数回调函数;函数:

void CppTest_StubCallback_processValues_case_1(CppTest_StubCallInfo* stubCallInfo, int* __return, int i, int j)
{
    // checking input value
    CPPTEST_ASSERT_INTEGER_EQUAL(-1, i);
    // modifying return value
    *__return = 150;
}

我们建议您将桩函数回调函数以及相关的测试用例定义保留在同一测试套件文件中。

您可以将桩函数回调函数定义为测试套件类的全局函数或静态成员函数(仅限 C++)。当启用“访问私有成员代码”检测功能时,这允许桩函数回调函数访问被测代码的私有类成员。

使用以下桩函数回调接口,可以用任何有效的 C 或 C++ 代码表示自定义桩函数逻辑:

  • 桩函数函数参数-可用作桩函数回调函数的参数
  • 桩函数函数返回值–可用作指向返回值持有人的"__return"指针
  • 桩函数函数类对象-可用作指向类对象的"__this"指针
  • 桩函数回调函数的当前调用数量 — 可用作 "int stubCallInfo->callNo"变量

此外,您可以在 Stub 回调函数中使用全局变量或全局函数,包括 C++test 单元测试 API(例如, CPPTEST_ASSERTCPPTEST_REPORT)。如果桩函数函数的原始定义可用,则也可以从桩函数回调函数中执行它。

(info) 您可以在【测试套件】文件中定义多个【桩函数回调函数】- 它们可以对应于相同的桩函数或多个不同的桩函数。

(info)  一个桩函数回调函数可以在单个测试用例中使用,也可以在许多不同的测试用例中共享。

(info)  一个桩函数一次只能激活一个桩函数回调函数(请参见 Stub Callback Registration)。

桩函数回调注册

为了使桩函数回调函数有效,必须对其进行注册。该函数通常在第一次调用桩函数函数之前在相关的测试用例中注册。在大多数情况下,应在调用被测函数之前进行注册。

使用以下 API 调用来注册桩函数回调函数:

CPPTEST_REGISTER_STUB_CALLBACK(<STUB_ID>, &<STUB_CALLBACK_NAME>)

此处:

  • <STUB_ID> 是唯一的桩函数标识符 (请参见 Stub Callback Execution)
  • <STUB_CALLBACK_NAME> 是用户定义的桩函数回调函数的名称

示例:

CPPTEST_REGISTER_STUB_CALLBACK("processValues", &CppTest_StubCallback_processValues_case_1);

您可以在多个测试用例中注册相同的桩函数回调函数,以便每个测试用例针对给定的桩函数使用相同的自定义逻辑。同样,可以在一个测试用例中注册不同的桩函数回调函数(针对不同的桩函数)。这使测试用例能够为多个桩函数提供自定义行为。在任何给定时间,给定桩函数只能有一个活跃的桩函数回调功能。

桩函数回调函数的生存期:

  • 激活:注册 CPPTEST_REGISTER_STUB_CALLBACK(<STUB_ID>, &<STUB_CALLBACK_NAME>)
  • 停用:测试用例结束或为同一桩函数注册了另一个桩函数回调函数 (same <STUB_ID>)

示例:

void test_case_1()
{
    ...
    // CppTest_StubCallback_foo activation:
    CPPTEST_REGISTER_STUB_CALLBACK("foo", &CppTest_StubCallback_foo);
    // CppTest_StubCallback_bar activation:
    CPPTEST_REGISTER_STUB_CALLBACK("bar", &CppTest_StubCallback_bar);
    ...
    callToFunctionUnderTest(); // will call foo() and bar()
    ...
} // end of test case: CppTest_StubCallback_foo deactivation, CppTest_StubCallback_bar deactivation


void test_case_2()
{
    ...
    // CppTest_StubCallback_foo activation:
    CPPTEST_REGISTER_STUB_CALLBACK("foo", &CppTest_StubCallback_foo);
    // CppTest_StubCallback_bar activation:
    CPPTEST_REGISTER_STUB_CALLBACK("bar", &CppTest_StubCallback_bar);
    ...
    callToFunctionUnderTest(); // will call foo() and bar()
    ...
    // CppTest_StubCallback_foo_1 activation, CppTest_StubCallback_foo deactivation
    CPPTEST_REGISTER_STUB_CALLBACK("foo", &CppTest_StubCallback_foo_1);


} // end of test case: CppTest_StubCallback_foo_1 deactivation, CppTest_StubCallback_bar deactivation

桩函数回调执行

如果定义并注册了桩函数回调函数,则每次调用相应的桩函数都会执行该函数。回调函数通过 CPPTEST_STUB_INVOKE_CALLBACK(), 来调用,如果在创建桩函数时启用了【启用桩函数回调】选项(默认情况下启用此选项),则该函数会自动添加到桩函数定义中。

示例:

/** Auto-generated stub definition for function: int processValues(int, int) */
int processValues (int i, int j) ;
int CppTest_Auto_Stub_processValues (int i, int j) 
{
    CPPTEST_STUB_CALLED("processValues");

    int __return = 0;

    /**
     * This section enables Dynamic Stub Configuration with Stub Callbacks.
     *
     * IMPORTANT: THIS COMMENT BLOCK SHOULD NOT BE DELETED OR MODIFIED
     *
     * 1. Define stub callback function in test suite file - use the following signature:
     *     void CppTest_StubCallback_SomeName(CppTest_StubCallInfo* stubCallInfo, int* __return, int i, int j)
     *
     * 2. Register stub callback in test case function - use the following code:
     *     CPPTEST_REGISTER_STUB_CALLBACK("processValues", &CppTest_StubCallback_SomeName);
     *
     * 3. Fill out the body of the stub callback function according to intent.
     * The following line may be used to call original function inside stub callback:
     *     *__return = ::processValues(i, j);
     */
    if (CPPTEST_STUB_HAS_CALLBACK()) {
        CPPTEST_STUB_CALLBACK_PARAMS(int* __return, int i, int j);
        CPPTEST_STUB_INVOKE_CALLBACK(&__return, i, j);

    } else {
        /* You can put additional stub logic here. */

    }

    return __return;
}


(info) 自动添加到桩函数定义的桩函数回调调用部分包含桩函数回调函数的默认签名和示例性的桩函数回调注册行,当您手动配置桩函数回调时,可以将其复制到测试套件文件中。

桩函数标识符

用于桩函数回调注册和桩函数回调执行的桩函数标识符必须唯一,以标识各个桩函数。默认情况下, C++test 生成的桩函数按照以下模式使用标识符:

[<parent::>]<function_name>

仅当桩函数函数是类或名称空间成员时,才添加<parent::>前缀。仅添加直接父级。对于模板类方法、父名称中省略了模板参数。

使用桩函数回调实现重载功能

C/C++test 对函数的所有重载版本使用相同的函数标识符(请参见桩函数标识符)。在对重载函数使用桩函数回调之前,请更新用于桩函数回调执行代码 (CPPTEST_STUB_CALLED()) 和桩函数回调注册的标识符,以确保它们是唯一的。这将使您能够区分重载的函数/方法的桩函数。

示例:

用于所有重载版本的 foo() 的默认标识符:

CPPTEST_STUB_CALLED("foo");

Foo(int) 的更新的标识符:

CPPTEST_STUB_CALLED("foo_int")

创建调用原始函数的桩函数

如果没有在测试用例中注册特定于测试用例的桩函数回调函数,则 C/C++test 允许您生成调用原始函数的桩函数。为此,请在 桩函数视图中启用以下选项 (请参见 桩函数视图中的配置桩函数选项) 或在测试配置中(请参见 执行选项卡设置-定义测试的执行方式):

  • 启用桩函数回调
  • 插入对原始函数的调用

启用这些选项后,C/C++test 将应用以下桩函数策略:

  1. 如果针对当前执行的测试注册了特定于测试案例的桩函数回调,则桩函数回调函数将用于桩函数原始函数。
  2. 如果没有为当前执行的测试注册特定于测试用例的桩函数回调,则桩函数将调用原始函数。结果,在测试用例执行期间将调用原始函数,而桩函数则充当“代理”。
  3. 如果没有 为当前执行的测试注册特定于测试用例的桩函数回调, 并且原始函数不可用,则 C/C++test 将使用您可以在桩函数定义中指定的自定义逻辑。

示例:


(info) 以下情况不支持调用原始函数:

  • 构造函数
  • 带省略号的功能
  • 纯虚函数
  • 具有内部链接的功能
  • 具有推论返回类型并且在任何标头中都不可见的函数
  • No labels