使用谷歌模拟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)