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

4

我目前正在使用纯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个回答

2
一个测试代码的效率通常不重要。它取决于你试图测试什么,但是重复的代码可能表示设计缺陷。
在您的情况下,您可以将mcp2515_read_register函数分为两部分:一个创建结构体,另一个处理SPI传输。
最佳的面向对象程序设计可能涉及以下模块:
- 仅关注实际通信的SPI驱动程序。 - 仅关注控制器的具体细节的CAN控制器驱动程序。 - 调用者(“main”或其他)。 - 用于CAN控制器驱动程序的测试代码:替换主函数。
SPI驱动程序将spi_frame_t声明为"opaque type",一种仅与SPI数据和通信相关的结构。SPI驱动程序之外没有人知道或需要知道此结构的内容。我不知道回调函数的作用,但它看起来不像与SPI驱动程序有关的东西。它更像是与调用SPI驱动程序的代码相关的东西。
CAN控制器驱动程序包括SPI驱动程序。它从SPI驱动程序中调用一个“构造函数”来创建帧,然后将该帧传递给SPI通信例程。然后,CAN控制器驱动程序没有紧密耦合到SPI功能。例如,在发现SPI中存在错误时,重新编写CAN控制器代码是没有意义的。如果您想在另一个项目中重复使用SPI驱动程序,也不应该需要CAN控制器。
测试用例将替换调用者(“main”)或CAN控制器代码,具体取决于您正在尝试测试程序的哪个部分。它使用与生产代码完全相同的函数。

这几乎就是应用程序的构建方式。回调函数在(异步)SPI传输完成时是必需的。因此,spi_frame_t与SPI实现无关,仅用于指示要传输的数据。我的原始问题仍未得到解答。如何避免在测试和实现之间重复代码。如果我的实现几乎是从我的测试中复制/粘贴了90%,那么测试有什么用处。 - Willem Melching
@WillemMelching 如果SPI帧与SPI无关,为什么要在其前缀中使用SPI?你要么给类型起了一个令人困惑的名称,要么你的CAN控制器代码正在处理它不应该关心的事情。 - Lundin
@WillemMelching 无论如何,SPI帧属于哪里并不重要,因为您仍然可以使用不透明类型和构造函数进行实现。这样,帧的创建与传输分离,您的测试代码可以像生产代码函数一样调用帧构造函数。您的应用程序没有这样做,而是使用了纯“过程式编程结构体”,其中应用程序代码与结构数据类型紧密耦合。这就是为什么您必须在测试用例中重复代码的原因。 - Lundin
如果你从测试中复制粘贴到代码中,那么你做错了。显然,在这种情况下测试将通过。我建议阅读一些单元测试方法,参见http://xunitpatterns.com/Behavior Verification.html和可能的http://martinfowler.com/articles/mocksArentStubs.html。 - Ross
1
@Ross 再次强调,这取决于他想要测试什么。你不能没有上下文地说复制/粘贴是错误的。 - Lundin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接