单元测试和实现之间的代码重复

时间:2014-11-20 12:16:19

标签: c unit-testing embedded tdd cmock

我目前正在开发一些用于纯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);
}

正如您所看到的,测试和实现之间的代码之间存在很多重复。

这是一个问题吗?我写错了吗?或者我是否应该为这种低级别的东西打扰测试呢?

1 个答案:

答案 0 :(得分:2)

测试代码的效率通常不重要。这取决于您要测试的内容,但重复的代码可能表明存在设计缺陷。

在您的情况下,您可能将mcp2515_read_register函数分为两部分:一部分用于创建结构,另一部分用于处理SPI传输。

最佳OO程序设计可能涉及以下模块:

  • SPI驱动程序仅关注实际通信。
  • CAN控制器驱动程序仅关注控制器的细节。
  • 来电者("主要"或其他)。
  • CAN控制器驱动程序的测试代码:替换main。

SPI驱动程序将spi_frame_t声明为 opaque类型,这是一种仅涉及SPI数据和通信的结构。 SPI驱动程序外部没有人知道或需要知道此结构的内容。我不知道回调函数的作用,但它看起来并不像SPI驱动程序。它看起来像是与调用SPI驱动程序的代码相关的东西。

CAN控制器驱动程序包含SPI驱动程序。它调用了一个"构造函数"从SPI驱动程序创建一个帧,然后将帧传递给SPI通信例程。然后,CAN控制器驱动程序与SPI功能没有紧密耦合。例如,重写CAN控制器代码没有意义,因为您在SPI中发现了一个错误。如果您想在另一个项目中重复使用SPI驱动程序,也不需要CAN控制器才能使用SPI。

测试用例要么替换调用者(" main"),要么替换CAN控制器代码,具体取决于您尝试测试的程序部分。它使用与生产代码完全相同的功能。