gmock可以用于存根C函数吗?

我是gmock的新手,所以我想知道如何在unit testing的测试函数中调用简单的C函数。

例:

int func(int a) { boolean find; // Some code find = func_1(); return find; } 

我搜索过gmock,在我的理解中,gmock没有提供存根简单C函数的function,因此我想问一下gmock是否提供了模拟或存根func_1

如果不是,如何在不更改源代码的情况下在我的测试代码中手动存根func_1 ? 我正在使用谷歌测试框架进行unit testing。

谢谢。

我最近发现自己处于同样的境地。 我不得不为用C编写的库编写unit testing,而这些库又依赖于其他用C语言编写的库。所以我想用gmock模拟所有依赖项的函数调用。 让我通过一个例子解释我的方法。

假设要测试的代码(库A)从另一个库lib_x_function()调用一个函数:

 lib_a_function() { ... retval = lib_x_function(); ... } 

所以,我想模拟库X.因此我在文件lib_x_mock.h编写了一个接口类和一个mock类:

 class LibXInterface { public: virtual ~LibXInterface() {} virtual int lib_x_function() = 0; } class LibXMock : public LibXInterface { public: virtual ~LibXMock() {} MOCK_METHOD0(lib_x_function, int()); } 

另外,我创建了一个源文件(比如lib_x_mock.cc ),它定义了实际C函数的存根。 这将调用mock方法。 请注意对mock对象的extern引用。

 #include lib_x.h #include lib_x_mock.h extern LibXMock LibXMockObj; /* This is just a declaration! The actual mock obj must be defined globally in your test file. */ int lib_x_function() { return LibXMockObj.lib_x_function(); } 

现在,在测试库A的测试文件中,我必须全局定义模拟对象,以便在测试和lib_x_mock.cc都可以访问它。 这是lib_a_tests.cc:

 #include lib_x_mock.h LibXMock LibXMockObj; /* This is now the actual definition of the mock obj */ ... TEST_F(foo, bar) { EXPECT_CALL(LibXMockObj, lib_x_function()); ... } 

这种方法非常适合我,我有几十个测试和几个模拟库。 但是,我有一些疑问,如果可以创建一个全局模拟对象 – 我在一个单独的问题中问这个,仍然等待答案。 除此之外,我对解决方案感到满意。


编辑:关于全局对象的问题可以通过在测试夹具的构造函数中创建对象,并在全局变量中存储指向该对象的指针来轻松解决。

但是,请注意我刚才发布的这个问题的替代答案。

我已经花了很长时间寻找使用googleMock模拟遗留c函数的解决方案而不更改现有代码,并且在最后几天我发现了以下非常好的文章: https ://www.codeproject.com/articles/1040972/using-googletest -and-googlemock的框架换EMB

今天我使用gmock编写了我的第一个c函数unit testing,并以bcm2835.c库( http://www.airspayce.com/mikem/bcm2835/ )中的两个函数为例进行了覆盆子Pi编程:这是我的解决方案:我正在使用gcc 4.8.3。 在Eclipse和Windows下。 请注意设置编译器选项-std = gnu ++ 11。

以下是我要测试的function

 int inits(void); void pinMode(uint8_t pin, uint8_t mode); int inits(){ return bcm2835_init(); } void pinMode(uint8_t pin, uint8_t mode){ bcm2835_gpio_fsel(pin, mode); } 

使用googleTest / googleMock包含和定义unit testing

 // MOCKING C-Functions with GMOCK :) #include  #include "gtest/gtest.h" #include "gmock/gmock.h" using namespace ::testing; using ::testing::Return; 

模拟BCM2835Libfunction

 class BCM2835Lib_MOCK{ public: virtual ~BCM2835Lib_MOCK(){} // mock methods MOCK_METHOD0(bcm2835_init,int()); MOCK_METHOD2(bcm2835_gpio_fsel,void(uint8_t,uint8_t)); }; 

创建一个TestFixture

 class TestFixture: public ::testing::Test{ public: TestFixture(){ _bcm2835libMock.reset(new ::testing::NiceMock()); } ~TestFixture(){ _bcm2835libMock.reset(); } virtual void SetUp(){} virtual void TearDown(){} // pointer for accessing mocked library static std::unique_ptr _bcm2835libMock; }; 

实例化模拟的lib函数

 // instantiate mocked lib std::unique_ptr TestFixture::_bcm2835libMock; 

假libfunction将Mocks与c函数连接起来

 // fake lib functions int bcm2835_init(){return TestFixture::_bcm2835libMock->bcm2835_init();} void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode){TestFixture::_bcm2835libMock->bcm2835_gpio_fsel(pin,mode);} 

从TestFixture为BCM2835创建unit testing类

 // create unit testing class for BCM2835 from TestFixture class BCM2835LibUnitTest : public TestFixture{ public: BCM2835LibUnitTest(){ // here you can put some initializations } }; 

使用googleTest和googleMock编写测试

 TEST_F(BCM2835LibUnitTest,inits){ EXPECT_CALL(*_bcm2835libMock,bcm2835_init()).Times(1).WillOnce(Return(1)); EXPECT_EQ(1,inits()) << "init must return 1"; } TEST_F(BCM2835LibUnitTest,pinModeTest){ EXPECT_CALL(*_bcm2835libMock,bcm2835_gpio_fsel( (uint8_t)RPI_V2_GPIO_P1_18 ,(uint8_t)BCM2835_GPIO_FSEL_OUTP ) ) .Times(1) ; pinMode((uint8_t)RPI_V2_GPIO_P1_18,(uint8_t)BCM2835_GPIO_FSEL_OUTP); } 

结果:)

 [----------] 2 tests from BCM2835LibUnitTest [ RUN ] BCM2835LibUnitTest.inits [ OK ] BCM2835LibUnitTest.inits (0 ms) [ RUN ] BCM2835LibUnitTest.pinModeTest [ OK ] BCM2835LibUnitTest.pinModeTest (0 ms) [----------] 2 tests from BCM2835LibUnitTest (0 ms total) 

希望它会有所帮助:) - 对我而言,这是一个非常有效的解决方案。

这是我对这个问题的另一个答案。 在第一个回答后的两年中,我开始明白GMock只是模拟C函数的错误框架。 在你有很多模拟function的情况下,我以前发布的答案太麻烦了。 原因是GMock使用Object Seams用模拟代码替换生产代码。 这依赖于C中不存在的多态类。

相反,要模拟C函数,您应该使用Link Seams ,它在链接时用模拟代码替换生产代码。 为此目的存在几个框架,但我最喜欢的是假function框架 ( FFF )。 看看它,它比GMock简单得多。 它在C ++应用程序中也能很好地工作。

对于感兴趣的人来说,这是Michael Feathers关于不同接缝类型的好文章 。

我在一个项目中有一个类似的案例,我正在进行unit testing。 我的解决方案是创建两个make文件,一个用于生产,一个用于测试。

如果函数func_1()在头文件中定义啊,并在a.cpp中实现,那么为了测试你可以添加一个新的源文件a_testing.cpp,它将实现所有函数啊作为存根。 对于unittesting,只需编译并链接a_testing.cpp而不是a.cpp,测试的代码将调用你的存根。

在a_testing.cpp中,您可以将调用转发给gmock对象,该对象将根据状态和参数设置常规和操作。

我知道它并不完美,但它可以在不改变生产代码或接口的情况下解决问题。

在每个UT中,我们都在尝试validation特定的行为。

当你很难/不可能(我们需要隔离我们的单位 )/花费大量时间(运行时间……)模拟特定行为时,你应该假装一些东西。

以显式方式使用“C”函数意味着该函数是您单元的一部分(因此您不应该模拟它…)。 在这个答案中,我解释了按原样测试方法的主动权(在编辑中)。 在我看来,你应该使用参数调用func ,这些参数会导致func_1模拟你想要validation的行为。

GMock基于编译假(宏),因此你不能做这样的事情。 要伪造’C’方法,你必须使用不同的工具,如Typemock Isolator ++ 。

如果你不想使用Isolator++ ,那么你应该重构你的方法; 将func(int a, )更改为func(int a, ) ,然后使用指针而不是func_1

我在这个答案中的图表可能有助于决定处理案件的方式。