如何在C语言中无getter/setter时对ADT进行单元测试?
嵌入式C中ADT单元测试的干净实践方案?
我正在重构嵌入式C代码,遵循James W. Grenning所著《Test-Driven Development for Embedded C》中的建议,将代码按**抽象数据类型(ADT)**划分为模块,类似Java中的类。但遇到一个实际问题:很多ADT并不需要getter和setter,核心只需要两个操作——从字节数组提取数据构建结构体,以及将ADT存储的数据显示在设备屏幕上(显示逻辑依赖外部静态库和屏幕驱动)。
我希望对提取字节数组数据并构建ADT的extract_tlv函数做单元测试,但由于ADT封装了结构体成员,没有暴露getter/setter,无法直接验证内部状态;如果调用display_tlv来测试,又需要在模拟器运行并mock驱动,完全不适合做单元测试。
以TLV(tag length value)缓冲区的ADT为例:
tlv.h
struct tlv typedef tlv_t; // 从字节缓冲区中提取TLV数据,构建tlv_t结构体 tlv_t * extract_tlv(const uint8_t *buffer, size_t buffer_length); // 将tlv结构体中的数据显示在设备屏幕上 int display_tlv(const tlv_t *tlv);
tlv.c
#include "tlv.h" typedef enum { TAG_A, TAG_B, ... } tlv_tag_t; struct tlv { tlv_tag_t tag; size_t length; uint8_t *value; }; tlv_t * extract_tlv(const uint8_t *buffer, size_t buffer_length) { tlv_t *tlv = (tlv_t *)calloc(1, sizeof(tlv_t)); if(!tlv) { return NULL; } // 提取缓冲区中的TLV数据并存储到tlv结构体 ... return tlv; } int display_tlv(const tlv_t *tlv) { // 访问tlv结构体字段并执行显示逻辑 ... }
假设输入缓冲区为0x0001000412345678(tag和length为uint16_t类型),调用extract_tlv后预期得到的结构体状态为:
tlv.tag = TAG_B, // 对应0x0001 tlv.length = 4, // 对应0x0004 tlv.value = {0x12, 0x34, 0x56, 0x78}, // 对应0x12345678
已尝试的方案与疑惑
我们曾尝试在tlv.h中用宏定义结构体成员,以此在测试代码中“绕过”封装:
修改后的tlv.h
#define TLV_STRUCT_MEMBER \ tlv_tag_t tag; \ size_t length; \ uint8_t *value; typedef enum { TAG_A, TAG_B, ... } tlv_tag_t; struct tlv typedef tlv_t; // 从字节缓冲区中提取TLV数据,构建tlv_t结构体 tlv_t * extract_tlv(const uint8_t *buffer, size_t buffer_length); // 将tlv结构体中的数据显示在设备屏幕上 int display_tlv(const tlv_t *tlv);
修改后的tlv.c
#include "tlv.h" struct tlv { TLV_STRUCT_MEMBER }; tlv_t * extract_tlv(const uint8_t *buffer, size_t buffer_length) { ... } int display_tlv(const tlv_t *tlv) { ... }
测试代码test_tlv.c
#include "tlv.h" struct test_tlv { TLV_STRUCT_MEMBER } typedef test_tlv_t; TEST_EXTRACT_TLV() { test_tlv_t *tlv = (test_tlv_t *)extract_tlv(...); TEST_ASSERT_EQUAL(4, tlv->length); ... }
这种通过强制类型转换访问结构体成员的方式感觉很hacky,我并不认可。另外我也有疑惑:只为单元测试实现getter和setter,属于“干净”的实践吗?
请问这种场景下的最佳“干净”实践是什么?有没有合适的解决方案?
内容的提问来源于stack exchange,提问作者kokopelli
相关产品推荐
相关产品推荐

