Using google mock for C code

后端 未结 3 1947
无人及你
无人及你 2020-12-05 10:41

I\'m maintaining a legacy project written in C and it\'s unfeasible to get it running with a C++ compiler. Since the code is cross compiled it is however possible to run uni

3条回答
  •  半阙折子戏
    2020-12-05 11:21

    I found a way to be able to mock bare C functions in google-mock.

    The solution is to declare foobar to be a weak alias that maps to foobarImpl. In production code you do not implement foobar() and for unit tests you provide an implementation that calls a static mock object.

    This solution is GCC specific but there are other compilers/linkers that provide weak aliasing.

    • rename the function void foobar(); to void foobarImpl();
    • add an attribute to the function foobar like: void foobar() __attribute__((weak, alias("foobarImpl") ));
    • if you want to have a non weak alias use a preproessor directive to remove the weak from the attributes.

    Hence:

    #pragma once
    void foobar();
    

    becomes

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

    and

    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
    

    This will tell the gnu linker to link calls of foobar() with foobarImpl() whenever there is no symbol called foobar()

    then add the testing code

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

    if this code is compiled and linked it will replace foobar with the mock call. if you really want to call foobar() you can still do add a default invocation.

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

提交回复
热议问题