使用谷歌模拟C代码

我正在维护用C编写的遗留项目,并且使用C ++编译器运行它是不可行的。 由于代码是交叉编译的,因此可以在主机环境中运行unit testing或类似操作。 因此,它也可以与C ++主机编译器连接,并使用google-test和google-mock。

谷歌模拟的某些function似乎非常诱人用于测试,如调用实际实现和设置调用期望。

我希望能够在C代码中使用它们。 我可以看到,确实可以在不使用vtable的情况下使用google-mock,但它需要模板。

有没有办法用google mock模拟裸C函数?

我发现了一种能够在google-mock中模拟裸C函数的方法。

解决方案是将foobar声明为映射到foobarImpl的弱别名。 在生产代码中,您没有实现foobar()而对于unit testing,您提供了一个调用静态模拟对象的实现。

此解决方案是GCC特定的,但还有其他编译器/链接器提供弱混叠。

  • 重命名函数void foobar(); 使void foobarImpl();
  • 向函数foobar添加一个属性,如: void foobar() __attribute__((weak, alias("foobarImpl") ));
  • 如果你想拥有一个非弱别名,请使用preproessor指令从属性中删除弱。

因此:

 #pragma once void foobar(); 

 // header.h #pragma once void foobar(); void foobarImpl(); // real implementation 

 extern "C" { #include "header.h" } // code.c void foobarImpl() { /* do sth */ } void foobar() __attribute__(( weak, alias ("foobarImpl") )); // declare foobar to be a weak alias of foobarImpl 

这将告诉gnu链接器在没有名为foobar()符号时将foobar()调用与foobarImpl()进行链接

然后添加测试代码

 struct FooInterface { virtual ~FooInterface() {} virtual void invokeFoo() const { } }; class MockFoo : public FooInterface { public: MOCK_CONST_METHOD0(invokeFoo, void()); } struct RealFoo : public FooInterface { virtual ~RealFoo() {} virtual void invokeFoo() const { foobarImpl(); } }; MockFoo mockFoo; RealFoo realFoo; void foobar() { mockFoo.invokeFoo(); } 

如果编译和链接此代码,它将使用模拟调用替换foobar 。 如果你真的想调用foobar()你仍然可以添加默认调用。

 ON_CALL(mockFoo, invokeFoo()) .WillByDefault(Invoke(&realFoo,&RealFoo::invokeFoo)); 

从谷歌模拟常见问题解答:

我的代码调用静态/全局函数。 我可以嘲笑它吗?
你可以,但你需要做一些改变。

通常,如果您发现自己需要模拟静态函数,则表明您的模块耦合得太紧(并且灵活性较低,可重用性较低,可测试性较差等)。 你最好定义一个小接口并通过该接口调用该函数,然后可以很容易地模拟它。 这最初是一项工作,但通常会很快收回成本。

这篇Google测试博客post非常出色。 看看这个。

您的问题专门提到Google Mock,但之后没有说明使用该框架的任何其他原因。 另一个答案建议使用似乎不必要的侵入性的解决方法。

因此,我希望我可以提出另一个有效的建议,而不必使用弱别名等。

我已经使用CppUTest( https://cpputest.github.io/ )与mock进行unit testing,成功地在几个大型的主要C项目(一些C ++)上。 嘲弄工作无需诉诸上述任何一种诡计。

不幸的是,项目文档有点弱,有些更好(如果有点敏捷教条)的信息和书中的例子(也见于PDF版)“嵌入式C的测试驱动开发” – James W Greening(ISBN-13: 978-1-934356-62-3)