DonBaka
DonBaka

Reputation: 455

How to mock base template class variable?

I am using google test for adding couple of unit tests in the program(C++). One of the class is using the member variable of the base template class.

For example:

template <typename foo>
class bar : public foo
{
    // let's say foo has a member variable alpha
    // using foo::alpha in bar
};

Now, for testing the bar class, I am mocking the foo class to be passed to bar. I mocked the functions of foo fine, but not sure how to handle the variables used from the base class? Like here I'm using the alpha variable.

For example:

struct Mockfoo
{
    // Mock Methods here
    // Not sure about variables??
};

bar<Mockfoo> b;

I am new to gtest/gmock. Have you encountered such cases and how to handle it? I am only interested in checking the behaviour of the function calls, so just wanted to somehow bypass the variable dependency.

Note: The variables are kind of complex, they need a couple of objects to initialize it, that means I need to mock them too. So, I am more biased towards some way of bypassing it.

Upvotes: 1

Views: 514

Answers (1)

Ari
Ari

Reputation: 7556

It's a bit odd (but doable) that you are testing a class bar and you want to mock its parent class foo. Ideally you want to keep your class-under-test and mocked collaborator classes separate.

If you want to do this, when you mock foo, you can mock alpha without the need for other objects. Say foo is originally defined as:

// Real foo used in production
struct foo {
  // Initializing alpha using other objects
  foo(OtherClass1 o1, OtherClass2 o2) : alpha(o1, o2) {}
  int SomeFunction() { return 0; }
  ComplexVariable alpha;
};

Then your mocked foo can be:

// Mocked complex variable
struct MockedComplexVariable {
 public:
  MOCK_METHOD(int, get, (), ());
};

struct Mockfoo {
  // Mock Methods here
  // Not sure about variables??
 public:
  MOCK_METHOD(int, SomeFunction, (), ());
  MockedComplexVariable alpha;  // ---> Doesn't need other objects!
};

Here is the complete example:

using ::testing::Return;

//-----------------------------------------------------------------------------
// Real classes used in production
//-----------------------------------------------------------------------------
class OtherClass1 {
  //...
};

class OtherClass2 {
  //...
};

class ComplexVariable {
 public:
  ComplexVariable(OtherClass1 o1, OtherClass2 o2) {}
  //...
};

// Real foo used in production
struct foo {
  // Initializing alpha using other objects
  foo(OtherClass1 o1, OtherClass2 o2) : alpha(o1, o2) {}
  int SomeFunction() { return 0; }
  ComplexVariable alpha;
};

//-----------------------------------------------------------------------------
// Mocked classes used in test
//-----------------------------------------------------------------------------
// Mocked complex variable
struct MockedComplexVariable {
 public:
  MOCK_METHOD(int, get, (), ());
};

struct Mockfoo {
  // Mock Methods here
  // Not sure about variables??
 public:
  MOCK_METHOD(int, SomeFunction, (), ());
  MockedComplexVariable alpha;  // ----> Doesn't need other objects!
};

template <typename foo>
class bar : public foo {
 public:
  // let's say foo has a member variable alpha
  // using foo::alpha in bar
  int UsingAlpha() { return foo::alpha.get() + foo::SomeFunction(); }
};

TEST(TestFoo, UsingAlpha) {
  bar<Mockfoo> b;
  EXPECT_CALL(b, SomeFunction()).WillOnce(Return(1)).WillOnce(Return(2));
  EXPECT_CALL(b.alpha, get()).WillOnce(Return(10)).WillOnce(Return(20));

  EXPECT_EQ(b.UsingAlpha(), 11);
  EXPECT_EQ(b.UsingAlpha(), 22);
}

Live example: https://godbolt.org/z/bs8PEWxxb

Upvotes: 0

Related Questions