我们在工作中为我们的低级网络代码使用一个简单的对象模型,其中结构指针被传递给伪装成方法的函数。我继承了大部分代码,这些代码充其量是由具有合格 C/C++ 经验的顾问编写的,并且我花了很多个深夜试图将代码重构为类似于合理结构的东西。
现在我想对代码进行单元测试,但考虑到我们选择的对象模型,我不知道如何模拟对象。请参见下面的示例:
示例标题(foo.h):
#ifndef FOO_H_
#define FOO_H_
typedef struct Foo_s* Foo;
Foo foo_create(TcpSocket tcp_socket);
void foo_destroy(Foo foo);
int foo_transmit_command(Foo foo, enum Command command);
#endif /* FOO_H_ */
示例源(foo.c):
struct Foo_s {
TcpSocket tcp_socket;
};
Foo foo_create(TcpSocket tcp_socket)
{
Foo foo = NULL;
assert(tcp_socket != NULL);
foo = malloc(sizeof(struct Foo_s));
if (foo == NULL) {
goto fail;
}
memset(foo, 0UL, sizeof(struct Foo_s));
foo->tcp_socket = tcp_socket;
return foo;
fail:
foo_destroy(foo);
return NULL;
}
void foo_destroy(Foo foo)
{
if (foo != NULL) {
tcp_socket_destroy(foo->tcp_socket);
memset(foo, 0UL, sizeof(struct Foo_s));
free(foo);
}
}
int foo_transmit_command(Foo foo, enum Command command)
{
size_t len = 0;
struct FooCommandPacket foo_command_packet = {0};
assert(foo != NULL);
assert((Command_MIN <= command) && (command <= Command_MAX));
/* Serialize command into foo_command_packet struct */
...
len = tcp_socket_send(foo->tcp_socket, &foo_command_packet, sizeof(foo_command_packet));
if (len < sizeof(foo_command_packet)) {
return -1;
}
return 0;
}
在上面的示例中,我想模拟TcpSocket对象,以便我可以将“foo_transmit_command”带入单元测试,但我不确定如何在没有继承的情况下进行此操作。我真的不想重新设计代码以使用 vtables,除非我真的必须这样做。也许有比嘲笑更好的方法?
我的测试经验主要来自C++,我有点害怕我可能会把自己画到这里来。我将非常感谢更有经验的测试人员的任何建议。
编辑:
就像 Richard Quirk 指出的那样,我想要覆盖的实际上是对“tcp_socket_send”的调用,我更愿意在链接测试时不从库中删除真正的 tcp_socket_send 符号,因为它是由其他测试调用的相同的二进制。
我开始认为这个问题没有明显的解决方案..