1

我正在从事一个针对 Silicon Labs 微控制器的项目。我想为蓝牙 SDK 调用创建一个包装器。SDK 库依赖很多,因此通过在该界面中创建外观,我可以避免将它们添加到我的测试中。请注意,此问题并非特定于 Silicon Labs 平台,但我将保留 SiLabs SDK 文件名,以防读者熟悉该平台。

我使用 CPPUTest 作为我的测试框架。我的代码是 C 和 C++ 的混合体,但就这个问题而言,它是 C。

例如,我的一个包装函数(在一个名为 的模块中Bluetooth_HW)将是

/* On "Bluetooth_HW.c" */

#include "native_gecko.h" // declares gecko_cmd_le_gap_bt5_set_adv_data()

// Set a new advertisement, either as advertisement packet or as a response.
bool BT_setAdvertisementMessage(uint8_t scanResponse, uint8_t adLength, uint8_t* newAdvertisement) {
    uint16_t result = gecko_cmd_le_gap_bt5_set_adv_data(0, scanResponse, adLength, newAdvertisement)->result;
    if (result != bg_err_success) {
        return false;
    } // Else, no errors setting the advertisement
    return true;
}

BT_setAdvertisementMessage()wraps gecko_cmd_le_gap_bt5_set_adv_data(),在native_gecko.hSDK 头文件中定义。我BT_setAdvertisementMessage()在中声明Bluetooth_HW.h并定义它bluetooth_HW.c。我需要设置广告消息的代码然后包含Bluetooth_HW.h而不是native_gecko.h,并且Bluetooth_HW.h很容易模拟。

我想测试一下Bluetooth_HW.c。我需要对此进行模拟native_gecko.h,因为我对运行它的代码不感兴趣(它是由制造商提供的,我相信它,而且我不是单元测试native_gecko,我是单元测试Bluetooth_HW)。通常,我会.h在测试中包含生产文件,以获取函数的声明,然后.c用我的假实现替换包含生产代码定义的文件。

我的问题是它native_gecko.h定义gecko_cmd_le_gap_bt5_set_adv_data()为标题内的内联,而不是在文件上执行它的更常见方法.c

我可以将自己包装native_gecko.h在一个只声明我需要的函数的标头上,并使我的代码包含该标头,但是我无法访问在 中声明的其他内容native_gecko.h,例如自定义类型和枚举。我无法将这些类型和枚举移动到包装器中,因为我无法从中删除它们,native_gecko.h然后编译器会抱怨被定义了两次,我不想 touch native_gecko.h,因为它是一个 SDK 文件。

所以,我的问题是如何模拟在其标头中定义代码的模块?

4

1 回答 1

1

我设法通过提供一个假的来让它工作native_gecko.h。然后,测试环境指向假标头而不是生产标头。就我而言,因为native_gecko.h它是巨大的,我只是通过手术添加了它工作所需的最少数量的元素。我只添加了所需函数的声明。虽然我可以模仿真实模块的行为并将它们添加为内联函数,但这需要将 CPPUTest 中的模拟框架包含到native_gecko.hC++ 中。当编译器尝试编译时Bluetooth_HW.c作为 C 代码并拉出标题,它会抱怨 C++ 代码的存在。通过将模拟函数定义添加到它们自己的文件中,我可以将模拟框架代码从头文件中删除,而我的原始生产代码 C 文件将只使用 C 代码进行编译。

粗略地说,步骤是

  1. 确保测试项目看不到真实的生产代码,native_gecko.h.
  2. 提供它的假版本,用任何已定义的函数替换声明(如果文件太大,例如 的情况native_gecko.h,只需为您的 Code-Under-Test 中使用的函数创建声明)。
  3. 为这些函数提供定义。

创建假标头并不理想,因为内容可能会随着 SDK 更新而改变,并且存在人为错误的空间,但这是我能想到的最干净的解决方案。

于 2021-12-15T11:54:41.137 回答