use*_*610 12 c unit-testing googletest gmock
我是gmock的新手,所以我想知道如何在单元测试的测试函数中调用简单的C函数.
例:
int func(int a)
{
boolean find;
// Some code
find = func_1();
return find;
}
Run Code Online (Sandbox Code Playgroud)
我搜索过gmock,在我的理解中gmock没有提供存根简单C函数的功能,因此我想问一下gmock是否提供了mock或stub的功能func_1
?
如果不是如何func_1
在不更改源代码的情况下手动在我的测试代码中存根?我正在使用谷歌测试框架进行单元测试.
谢谢.
Geo*_* P. 16
我最近发现自己处于同样的境地.我不得不为用C编写的库编写单元测试,而这些库又依赖于其他用C语言编写的库.所以我想用gmock模拟所有依赖项的函数调用.让我通过一个例子解释我的方法.
假设要测试的代码(库A)从另一个库调用函数,lib_x_function()
:
lib_a_function()
{
...
retval = lib_x_function();
...
}
Run Code Online (Sandbox Code Playgroud)
所以,我想模拟库X.因此我在一个文件中编写了一个接口类和一个mock类lib_x_mock.h
:
class LibXInterface {
public:
virtual ~LibXInterface() {}
virtual int lib_x_function() = 0;
}
class LibXMock : public LibXInterface {
public:
virtual ~LibXMock() {}
MOCK_METHOD0(lib_x_function, int());
}
Run Code Online (Sandbox Code Playgroud)
另外,我创建了一个源文件(比方说lib_x_mock.cc
),它定义了实际C函数的存根.这将调用mock方法.请注意对extern
mock对象的引用.
#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();
}
Run Code Online (Sandbox Code Playgroud)
现在,在测试库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());
...
}
Run Code Online (Sandbox Code Playgroud)
这种方法对我来说非常有效,我有几十个测试和几个模拟库.但是,我有一些疑问是否可以创建一个全局模拟对象 - 我在一个单独的问题中问这个并仍在等待答案.除此之外,我对解决方案感到满意.
编辑:关于全局对象的问题可以通过在测试夹具的构造函数中创建对象,并且只是在全局变量中存储指向该对象的指针来轻松解决.
但是,请注意我刚才发布的这个问题的替代答案.
小智 5
我已经花了很长时间寻找使用googleMock模拟遗留c函数的解决方案,而不更改现有代码,最后几天我发现了以下非常好的文章:https://www.codeproject.com/articles/1040972/using-googletest -and-googlemock的框架换EMB
今天我用gmock编写了我的第一个c函数单元测试,并以bcm2835.c库(http://www.airspayce.com/mikem/bcm2835/)中的两个函数为例进行了覆盆子Pi编程:这是我的解决方案:我正在使用gcc 4.8.3.在Eclipse和Windows下.请注意设置编译器选项-std = gnu ++ 11.
以下是我要测试的功能
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);
}
Run Code Online (Sandbox Code Playgroud)
使用googleTest/googleMock包含和定义单元测试
// MOCKING C-Functions with GMOCK :)
#include <memory>
#include "gtest/gtest.h"
#include "gmock/gmock.h"
using namespace ::testing;
using ::testing::Return;
Run Code Online (Sandbox Code Playgroud)
模拟BCM2835Lib功能
class BCM2835Lib_MOCK{
public:
virtual ~BCM2835Lib_MOCK(){}
// mock methods
MOCK_METHOD0(bcm2835_init,int());
MOCK_METHOD2(bcm2835_gpio_fsel,void(uint8_t,uint8_t));
};
Run Code Online (Sandbox Code Playgroud)
创建一个TestFixture
class TestFixture: public ::testing::Test{
public:
TestFixture(){
_bcm2835libMock.reset(new ::testing::NiceMock<BCM2835Lib_MOCK>());
}
~TestFixture(){
_bcm2835libMock.reset();
}
virtual void SetUp(){}
virtual void TearDown(){}
// pointer for accessing mocked library
static std::unique_ptr<BCM2835Lib_MOCK> _bcm2835libMock;
};
Run Code Online (Sandbox Code Playgroud)
实例化模拟的lib函数
// instantiate mocked lib
std::unique_ptr<BCM2835Lib_MOCK> TestFixture::_bcm2835libMock;
Run Code Online (Sandbox Code Playgroud)
假lib函数用于将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);}
Run Code Online (Sandbox Code Playgroud)
从TestFixture为BCM2835创建单元测试类
// create unit testing class for BCM2835 from TestFixture
class BCM2835LibUnitTest : public TestFixture{
public:
BCM2835LibUnitTest(){
// here you can put some initializations
}
};
Run Code Online (Sandbox Code Playgroud)
使用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);
}
Run Code Online (Sandbox Code Playgroud)
结果:)
[----------] 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)
Run Code Online (Sandbox Code Playgroud)
希望它会有所帮助:) - 对我而言,这是一个非常有效的解决方案.
在每个 UT 中,我们都试图验证特定的行为。
当它非常困难/不可能(我们需要隔离我们的单元)/花费大量时间(运行时间..)来模拟特定行为时,你应该伪造一些东西。
以显式方式使用“C”函数意味着该函数是您的单元的一部分(因此您不应该嘲笑它......)。在这个答案中,我解释了按原样测试该方法的举措(在编辑中..)。在我看来,您应该使用导致模拟您想要验证的行为的func
参数进行调用。func_1
GMock
基于编译假(宏),因此你不能做这样的事情。要伪造“C”方法,您必须使用不同的工具,例如Typemock Isolator++。
如果你不想使用Isolator++
,那么你应该重构你的方法;更改func
为func(int a, <your pointer the function>)
,然后使用指针代替func_1
。
我在这个答案中的图表可能有助于决定处理您的案件的方式。