我目前正在开发一些用于纯C的嵌入式平台的低级驱动程序。我使用unity + cmock作为单元测试框架。
然而,在编写低级别的东西时,我经常遇到以下模式:
测试:
void test_mcp2515_read_register(void)
{
spi_frame_t expected_frame = {{0}};
expected_frame.tx_length = 2;
expected_frame.rx_length = 3;
expected_frame.tx_data[0] = MCP2515_READ_CMD;
expected_frame.tx_data[1] = TEST_ADDR;
expected_frame.callback = callback_test;
spi_transmit_ExpectAndReturn(expected_frame, true);
mcp2515_read_register(TEST_ADDR, callback_test);
}
实现:
void mcp2515_read_register(uint8_t addr, spi_callback callback)
{
spi_frame_t frame = {{0}};
frame.tx_length = 2;
frame.rx_length = 3;
frame.tx_data[0] = MCP2515_READ_CMD;
frame.tx_data[1] = addr;
frame.callback = callback;
spi_transmit(frame);
}
正如您所看到的,测试和实现之间的代码之间存在很多重复。
这是一个问题吗?我写错了吗?或者我是否应该为这种低级别的东西打扰测试呢?
答案 0 :(得分:2)
测试代码的效率通常不重要。这取决于您要测试的内容,但重复的代码可能表明存在设计缺陷。
在您的情况下,您可能将mcp2515_read_register函数分为两部分:一部分用于创建结构,另一部分用于处理SPI传输。
最佳OO程序设计可能涉及以下模块:
SPI驱动程序将spi_frame_t
声明为 opaque类型,这是一种仅涉及SPI数据和通信的结构。 SPI驱动程序外部没有人知道或需要知道此结构的内容。我不知道回调函数的作用,但它看起来并不像SPI驱动程序。它看起来像是与调用SPI驱动程序的代码相关的东西。
CAN控制器驱动程序包含SPI驱动程序。它调用了一个"构造函数"从SPI驱动程序创建一个帧,然后将帧传递给SPI通信例程。然后,CAN控制器驱动程序与SPI功能没有紧密耦合。例如,重写CAN控制器代码没有意义,因为您在SPI中发现了一个错误。如果您想在另一个项目中重复使用SPI驱动程序,也不需要CAN控制器才能使用SPI。
测试用例要么替换调用者(" main"),要么替换CAN控制器代码,具体取决于您尝试测试的程序部分。它使用与生产代码完全相同的功能。