3

I have a class that is inherited from another class as mentioned below:

class A
{
public:
    virtual void Show(){}
};

class B : public A
public:
    void BMethod1(){Show()}
};

Now I am writing test cases for class B - so I have mocked class A :

class MockA : public A
{
    MOCK_METHOD0(Show, void());
};

Below is my Google Test framework test case:

TEST(BTEST , ShowMethod)
{
    B bobj;
    MockA aobj;
    EXPECT_CALL(aobj , Show());
    bobj.BMethod1(); // updated as from bobj.METHOD0()
}

But the test cases is calling the actual A::Show() implementation - how can call the Mocked version of MockA::Show() in such a case?

====================UPDATE=================================

Well the below implementation did the trick for me:

class A
{
public:
    virtual void Show(){}
};

class B : public A
public:
    void BMethod1(){Show()}
};

class BMock : public B
{
public:
   MOCK_METHOD0(Show, void());
};

Now use BMock object to test you class B required methods

273K
  • 29,503
  • 10
  • 41
  • 64
Programmer
  • 8,303
  • 23
  • 78
  • 162

4 Answers4

0

First off:

    bobj.METHOD0();

is totally wrong. METHOD0 is no valid symbol to access a mocked function.

What you want to test is that B::BMethod1() calls A::Show(), right?
So change that line to

    bobj.BMethod1();

You can change class B to take it's base class implementation as a template parameter:

class A
{
public:
    virtual void Show(){}
 // ^^^^^^^ See note 1
};

template<class Base>
class B : public Base
public:
    void BMethod1(){Show()}
};

Then you use

B<A> bobj;
bobj.BMethod1();

in your production code, and

B<MockA> bobj;
EXPECT_CALL(bobj , Show());
bobj.BMethod1(); // <<< trigger the expectation

in your unit test code.


As a side node:

It's a well known pattern to inject base classes through template type parameters called Mixin.
Though Mixins are mainly meant to provide piecewise implementations of interfaces, which are mainly meant to compose public interface implementations.

However, hitting such case when trying to unit test a class regarding those manners, would automatically lead me to the question, if I have a design flaw there:

Is B really an A, or is it rather meant to use an instance of A as an owned or referenced member variable?

If I'm coming up with the need to test such in a unit test, I'd consider refactoring class B to something like

class B {
    A& a_;
public:
    B(A& a) a_(a) {}
    void BMethod1() { a_.Show(); }
};

And adapt the test scenarios accordingly:

TEST(BTEST , ShowMethod)
{
    MockA aobj;
    B bobj(aobj);
    EXPECT_CALL(aobj , Show());
    bobj.BMethod1();
}

As for your comment

The intention is that the test case can return mocked values - EXPECT_CALL(mMockA, show()) .WillOnce(Return(false));

This should work with the example above:

EXPECT_CALL(bobj, Show()) .WillOnce(Return(false));

But requires that Show() is declared like

virtual bool Show();

in class A and like

MOCK_METHOD0(Show, bool());

in the MockA class.


1)The virtual declaration is necessary in order to allow MockA to override the original implementation.

user0042
  • 7,917
  • 3
  • 24
  • 39
0

You have to make Show() virtual to get MockA::Show() instead of A::Show().

Nayfe
  • 2,130
  • 13
  • 18
  • I tried that but still the same issue - can you please provide the method implementation in details – Programmer Dec 02 '17 at 06:36
  • Be carefull to put `public` keyword in MockA class too – Nayfe Dec 02 '17 at 06:46
  • something like this ? `class A { public: virtual void Show(){} }; class MockA : public A { public: MOCK_METHOD0(Show, void()); };` – Nayfe Dec 02 '17 at 07:02
  • @Nayfe Your answer doesn't really solves the OP's problem, but states a necessary fact to enable `MockA` to override that function. – user0042 Dec 02 '17 at 07:04
0

Well the below implementation did the trick for me:

class A
{
public:
    virtual void Show(){}
};

class B : public A
public:
    void BMethod1(){Show()}
};

class BMock : public B
{
public:
   MOCK_METHOD0(Show, void());
};

Now use BMock object for your test cases

Programmer
  • 8,303
  • 23
  • 78
  • 162
0

You can use Isolator++ to create the test without the setup:

class A
{
public:
    void Show() {}
};

class B : public A
{
public:
    void BMethod1() { Show(); }
};

TEST(BTEST, ShowMethod)
{
    B bobj;
    auto aobj = FAKE<A>();

    bobj.BMethod1();

    ASSERT_WAS_CALLED(aobj->Show());
}
Sam
  • 182
  • 6