Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can gmock be used for stubbing C functions?

I am new to gmock, so I want to know how can I stub simple C function called in a function under test for Unit Testing.

Example:

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

I have searched about gmock and in my understanding gmock does not provide functionality to stub simple C functions, therefore I want to ask does gmock provides functionality to mock or stub func_1?

If not how can I stub func_1 manually in my test code without changing source code? I am using google test framework for unit testing.

Thanks.

like image 470
SRehman Avatar asked Aug 13 '15 13:08

SRehman


3 Answers

This is another answer of mine to this question. In the two years that passed since the first answer, I came to understand that GMock is simply the wrong framework for mocking C functions. In situations where you have a lot of functions to mock, my previously posted answer is simply too cumbersome. The reason is that GMock uses Object Seams to replace production code with mock code. This relies on polymorphic classes, which don't exist in C.

Instead, to mock C functions, you should use Link Seams, which replace the production code with the mock code at link time. Several frameworks exist for this purpose, but my favorite one is the Fake Function Framework (FFF). Check it out, it's a lot simpler than GMock. It also works perfectly well in C++ applications.

For the interested, here is a good article by Michael Feathers about the different seam types.

like image 140
Georg P. Avatar answered Sep 20 '22 12:09

Georg P.


I was looking already a long time for a solution to mock legacy c-functions with googleMock without changing existing code and last days I found the following really great article: https://www.codeproject.com/articles/1040972/using-googletest-and-googlemock-frameworks-for-emb

Today I wrote my first unit test for c-functions using gmock and took as example two functions from the bcm2835.c library (http://www.airspayce.com/mikem/bcm2835/) for raspberry Pi programming: Here is my solution: I'm using the gcc 4.8.3. under Eclipse and Windows. Be Aware to set the Compiler option -std=gnu++11.

Here are my functions to be tested

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);
}

Includes and defines for unit testing with googleTest / googleMock

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

Mock BCM2835Lib functions

class BCM2835Lib_MOCK{
public:
    virtual ~BCM2835Lib_MOCK(){}

    // mock methods
    MOCK_METHOD0(bcm2835_init,int());
    MOCK_METHOD2(bcm2835_gpio_fsel,void(uint8_t,uint8_t));
};

Create a 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;
};

Instantiate mocked lib functions

// instantiate mocked lib
std::unique_ptr<BCM2835Lib_MOCK> TestFixture::_bcm2835libMock;

Fake lib functions to connect Mocks with the c-functions

// 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);}

Create unit testing class for BCM2835 from TestFixture

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

Write the Tests using googleTest and 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);
}

Results :)

[----------] 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)

Hope it will help :) - for me this is a really working solution.

like image 8
matthandi Avatar answered Sep 20 '22 12:09

matthandi


You can use the Cutie library to mock C function GoogleMock style.
There's a full sample in the repo, but just a taste:

INSTALL_MOCK(close);
CUTIE_EXPECT_CALL(fclose, _).WillOnce(Return(i));
like image 2
MrDor Avatar answered Sep 20 '22 12:09

MrDor