26

I just started working on unit testing (using BOOST framework for testing, but for mocks I have to use Google Mock) and I have this situation :

class A
{
static int Method1(int a, int b){return a+b;}
};

class B
{
static int Method2(int a, int b){ return A::Method1(a,b);}
};

So, I need to create mock class A, and to make my class B not to use real Method1 from A class, but to use mock.

I'm not sure how to do this, and I could not find some similar example.

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Jonhtra
  • 897
  • 2
  • 12
  • 18
  • I'm not familiar with gmock, but couldn't you just link `B.o` and `mockA.o`? – Beta Jan 20 '12 at 13:54
  • As far as I know, there is some different way dealing with static methods. I could probably solve this with making Method1 to be virtual, and to add constructor in class B, so it looks something like B(A &a):a_in_class_b(a){}, and then call of Method1 would look like this : a_in_class_b->Method1(); But I want to see if there is some other way. – Jonhtra Jan 20 '12 at 14:01

3 Answers3

34

You could change class B into a template :

template< typename T >
class B
{
public:
static int Method2(int a, int b){ return T::Method1(a,b);}
};

and then create a mock :

struct MockA
{
  static MockCalc *mock;
  //This class is passed as template type during class B object creation in unit test environment
  static int Method1(int a, int b){ return mock->Method1(a,b);}
};
class MockCalc {
 public:
  MOCK_METHOD2(Method1, int(int,int));
};

Before every test, initialize the static mock object MockA::mock.

Another option is to instead call directly A::Method1, create a functor object (maybe std::function type) in class B, and call that in the Method2. Then, it is simpler, because you would not need MockA, because you would create a callback to MockCalc::Method1 to this object. Something like this :

class B
{
public:
static std::function< int(int,int) > f;
static int Method2(int a, int b){ return f(a,b);}
};

class MockCalc {
 public:
  MOCK_METHOD2(Method1, int(int,int));
};

and to initialize it :

MockCalc mock;
B::f = [&mock](int a,int b){return mock.Method1(a,b);};
BЈовић
  • 62,405
  • 41
  • 173
  • 273
1

jomock is one of the feasible solutions for Windows application case

class A
{
public:
    static int Method1(int a, int b) { return a + b; }
};

class B : public A
{
public:
    static int Method2(int a, int b){
        return A::Method1(a, b);
    }
};


TEST(JoMock, Method1Test)
{
    EXPECT_CALL(JOMOCK(A::Method1), JOMOCK_FUNC(_, _))
        .WillRepeatedly(Return(3));

    EXPECT_EQ(B::Method2(1, 3), 3);
}

B::Method2(1, 3) returns 3 in this case.

  • 2
    This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/low-quality-posts/30750413) – zkoza Jan 06 '22 at 09:05
  • Well. the original question was "how to mock static functions", and I also have looked for the way to mock static or non-virtual method to avoid modification of legacy source code. "jomock" provides a solution with simple syntax by using function hook internally. – Hyugrae Cho Jan 07 '22 at 09:03
  • Well, the problem I see is that your answer is kind of side remark, and as such it would suffice if you left a simple comment under the question, pointing out that jomock offers another solution for Windows. – zkoza Jan 07 '22 at 09:36
0

A variant version based on BЈовић's answer that allows not to use template (and error-prone explicit template specialization if your implementation is not in the header files). However, this will need to make the class A not static anymore.

First, create an interface class

class AIf
{
int Method1(int a, int b) = 0;
};

Let your class A implements AIf

class A : AIf
{
int Method1(int a, int b){return a+b;}
};

Then in your class B, add a static pointer to the AIf

class B
{
static AIf* impl = nullptr;
static int Method2(int a, int b) {return impl->Method1(a, b)}
};

When GMock, just do

class MockA : AIf {
MOCK_METHOD2(Method1, int(int a, int b));
};

Then in your tests, set the impl before calling any functions

MockA mockA;
EXPECT_CALL(...);

B::impl = &mockA;
B::Method2(a, b);