I have a class A such as :
// .h
class A {
public:
A();
void init();
private:
B* b;
C* c;
};
// .cpp
A::A()
{
b = new B();
c = new C();
}
A::init()
{
if (b->foo()){
// doing hardware operations
c->on();
}
else
{
// not doing hardware operations
}
}
with b.foo()
a method a B returning a boolean value depending a specific B conditions and c::on()
some method doing operations on hardware.
I'm unit testing class A with gtest / gmock. I know that theorically what is private should remain private, but the whole purpose of my A::init method is to do a specific operation depending on the result of b::foo() which i cannot mock has b
is private.
Is there a way to verify that depending on b::foo() result, my public method A is doing the right operation ?
You need dependency injection.
Assuming that B
and C
are representing direct operation on hardware you should abstract this functionality to be able to mock hardware (those B
and C
).
This can go like this:
// InterfaceBC.h
class IB {
public:
virtual ~IB() { }
virtual bool foo() const = 0;
};
class IC {
public:
virtual ~IC() { }
virtual void on() = 0;
};
// A.h
class A {
public:
explicit A(IB* instanceB, IC* instanceC);
void init();
private:
IB* const b;
IC* const c;
};
// A.cpp
A::A(IB* instanceB, IC* instanceC)
: b { instanceB }
, c { instanceC }
{
}
void A::init()
{
if (b->foo()) {
// doing hardware operations
c->on();
} else {
// not doing hardware operations
}
}
Then you can write proper test for it:
// A_test.cpp
using testing::Return;
class MockB : public IB {
public:
MOCK_METHOD(bool, foo, (), (const override));
};
class MockC : public IC {
public:
MOCK_METHOD(void, on, (), (override));
};
class StackOverflowTestA : public ::testing::Test
{
public:
MockB mockB;
MockC mockC;
A underTest{&mockB, &mockC};
};
TEST_F(StackOverflowTestA, initOnFooSuccessCOnIsCalled)
{
EXPECT_CALL(mockB, foo()).WillOnce(Return(true));
EXPECT_CALL(mockC, on()).Times(1);
underTest.init();
}
TEST_F(StackOverflowTestA, initOnFooFailureCOnIsNotCalled)
{
EXPECT_CALL(mockB, foo()).WillOnce(Return(false));
EXPECT_CALL(mockC, on()).Times(0);
underTest.init();
}