ansonn / C-Mock

C Mock is a Google Mock extension allowing for mocking functions.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

C Mock - Google Mock Extension

Build Status

Overview

C Mock is Google Mock's extension allowing a function mocking.

This is neither a patch to nor fork of Google Mock. This is just a set of headers providing a way to use tools for mock methods with mock functions in tests.

C Mock is not intended to promote a bad design. Its goal is to aid the developers test their code.

Before use of C Mock following reading is recommended:

Requirements

  • Google Mock (1.6 or newer)
  • GNU/Linux platform that Google Mock supports

Guide

C Mock requires no prior build, it is just a set of header files you include in your code.

Using CMockMocker class

C Mock comes with CMockMocker class and CMOCK_MOCK_FUNCTION* set of macros.

Creating mock

Suppose you want to mock int divide(int, int) and int substract(int, int) functions declared in math.h header file. To do that you can create a single mock class for both of them called MathMocker:

  • math_mocker.h:
#include <cmock/cmock.h>

#include "math.h"

class MathMocker : public CMockMocker<MathMocker>
{
public:
    MOCK_METHOD2(divide, int(int, int));
    MOCK_METHOD2(substract, int(int, int));
};
  • math_mocker.cc:
#include "math_mocker.h"

CMOCK_MOCK_FUNCTION2(MathMocker, divide, int(int, int));
CMOCK_MOCK_FUNCTION2(MathMocker, substract, int(int, int));

Specifying expectations

To specify the expectations you use Google Mock's macros as you would normally do. The functions are mocked as long as its corresponding mocker class instance exists. This allows to easily control when the functions are mocked.

{
    MathMocker mock;

    EXPECT_CALL(mock, divide(1, 1)).WillOnce(Return(11));
    ASSERT_EQ(11, divide(1, 1)); // calling the mock

    EXPECT_CALL(mock, substract(1, 2)).WillOnce(Return(12));
    ASSERT_EQ(12, substract(1, 2)); // calling the mock
}

ASSERT_EQ(1, divide(1, 1)); // calling the real function
ASSERT_EQ(-1, substract(1, 2)); // calling the real function

Using macros (deprecated)

C Mock comes with four macros:

  • DECLARE_FUNCTION_MOCK* and IMPLEMENT_FUNCTION_MOCK*
  • EXPECT_FUNCTION_CALL
  • ON_FUNCTION_CALL

These macros do what theirs' method counterparts do MOCK_METHOD_*, EXPECT_CALL and ON_CALL, respectively. There are small differences though.

Creating mock

In fact both DECLARE_FUNCTION_MOCK* and IMPLEMENT_FUNCTION_MOCK* stand for a series of macros for defining and implementing a function mock, respectively. These macros take three arguments: a mock class name, a function name and a function prototype.

C Mock internally redefines a function being mocked. Because only one implementation of a function might exist in an executable, a splitting of a declaration and implementation is necessary. Especially, if mocking a certain function takes place in a more than one compilation unit. Therefore declaration should be put in a header file whereas implementation in a source file.

C Mock has no knowledge whether a mocked function is declared with a name mangling - whether this is a pure C function or a C++ function. Therefore C Mock does not redeclare mocked function. Original function prototype declaration should be used (i.e. use of original function header file).

Suppose you want to mock int add(int, int) function declared in math.h header file. To do that you can create AddFunctionMock mock class:

  • add_function_mock.h

    #include <cmock/cmock.h>
    
    #include "math.h" // use original function declaration
    
    DECLARE_FUNCTION_MOCK2(AddFunctionMock, add, int(int, int));
  • add_function_mock.cc

    IMPLEMENT_FUNCTION_MOCK2(AddFunctionMock, add, int(int, int));

Specifying expectations

EXPECT_FUNCTION_CALL and ON_FUNCTION_CALL do exactly what theirs' method equivalents. Both take two arguments: a mock class instance and the arguments you expect - there is no need to repeat function name since it is already known at this point. Suppose we expect add function to be called once with arguments 1 and 2, and want it to return 12:

AddFunctionMock mock;
EXPECT_FUNCTION_CALL(mock, (1, 2)).WillOnce(::testing::Return(12));

A function is mocked as long as its corresponding mock class instance exists. This allows to control when a function is mocked.

{
    AddFunctionMock mock;
    add(1, 2); // calling the mock
}

add(1, 2); // calling the real function

Still you might want to use a mocked function's real implementation. Each mock class exports static real class field which holds pointer to a real function.

AddFunctionMock mock;
EXPECT_FUNCTION_CALL(mock, (1, 2)).WillOnce(::testing::Invoke(AddFunctionMock::real));
foo(1, 2); // calling the real function

Building

C Mock uses internally some tricks specific to GNU/Linux platform and a test building requires a few additional steps.

Firstly, all functions you want to mock must be in a dynamic library. If it includes your project-specific functions you must put them into a dynamic library. In such a circumstances it seems reasonable to build all code under test as a dynamic library. Selecting only those parts that you are going to mock might be tedious and cumbersome.

Secondly, you must pass the following options to a linker when building a test executable:

  • -rdynamic - adds all symbols to dynamic symbol table
  • -Wl,--no-as-needed - links with library when during static linking there are no dependencies to it
  • -ldl - links with dynamic linking loader library

C Mock comes with cmock-config tool to hide all these details away from you. Run

cmock-config --cflags

and

cmock-config --libs [path to libgmock [path to libgtest]]

to get the compilations and linker options, respectively.

Note: Since it is not recommended to install a pre-compiled version of Google Test many distributions don't provide such libs anymore. You need to download and compile those libs as described in Google Test. For the linker to find libgmock and libgtest you can pass the paths to those libs to the cmock-config script. If you omit the path to libgtest it defaults to "pathToLibgmock/libgtest".

Let's say you built a code under test into libfoo.so and put a test code in bar.cc. To build your test executable you would run:

g++ `cmock-config --cflags` -c bar.cc -o bar.o
g++ `cmock-config --libs` -pthread -lfoo bar.o -o bar # Google Test requires -pthread

When building code under test as a dynamic library it is handy to specify soname as an absolute path name. Then when test executable is run no additional environment setup is required for the dynamic linking loader to locate your library (i.e. setting LD_LIBRARY_PATH).

Installation

To install run:

make install

To uninstall run:

make uninstall

By default installation PREFIX is /usr/local. You can change it as follows:

make install PREFIX=/usr

Test

If your platform is supported and Google Test is installed, the following commands should succeed:

make
make test

Tests are quite simple and are a good source of usage examples.

References

About

C Mock is a Google Mock extension allowing for mocking functions.

License:BSD 2-Clause "Simplified" License


Languages

Language:C++ 93.3%Language:C 4.0%Language:Shell 1.5%Language:Makefile 1.2%