I have a class that calls a mocked function in the initializer list. I want to use EXPECT_CALL in order to verify that the mocked function is called only once. The problem is that I can't use the macro before the constructor because it's the first function that runs, neither after it because the mocked function is called in the constructor.
For example: ui.cpp
class UI {
public:
UI() = default;
~UI() = default;
virtual std::string get_name() {
std::string name;
std::cin >> name;
return name;
}
};
foo.cpp
class Foo {
public:
Foo(UI& ui) : m_name(ui.get_name()) {}
~Foo() = default;
};
mock_ui.hpp
class MockUI : public UI {
MockUI() : UI() = default;
~MockUI() = default;
MOCK_METHOD(std::string, get_name, (), (override));
};
The problem occurs here: foo_test.cpp
class FooTest : ::testing::Test {
public:
// I want to call EXPECT_CALL(m_ui, get_name()) before this line executes.
FooTest() : m_foo(MockUI()) {}
~FooTest() = default;
protected:
void SetUp() override {}
void TearDown() override {}
Foo m_foo;
MockUI m_ui;
};
I tried initializing the Foo
object in the SetUp()
function, but Foo doesn't have default constructor so it has to be initialized in the FooTest
constructor.
The Solution?
The only idea I have is to call EXPECT_CALL()
in MockUI constructor like this:
mock_ui.hpp
class MockUI : public UI {
MockUI() : UI() {
EXPECT_CALL(*this, get_name());
}
~MockUI() = default;
MOCK_METHOD(std::string, get_name, (), (override);
};
The problem is that I might use MockUI without calling get_name()
or calling it multiple times, but this is the best solution I have.
Any other suggestions?
CodePudding user response:
You can defer initialization of Foo
by using a pointer:
class FooTest : ::testing::Test {
public:
FooTest()
{
EXPECT_CALL(m_ui, get_name());
m_foo = std::make_unique<Foo>(m_ui);
}
protected:
std::unique_ptr<Foo> m_foo;
MockUI m_ui;
};
Or by adding a parent class that will initialize MockUI
first:
class FooTestHelper: public ::testing::Test
{
public:
FooTestHelper() { EXPECT_CALL(m_ui, get_name()); }
protected:
MockUI m_ui;
};
class FooTest : public FooTestHelper
{
public:
FooTest(): FooTestHelper{}, m_foo{m_ui} {}
private:
Foo m_foo;
};
Also, as the commenters noticed, UI
is passed to Foo
by value, which means no inheritance would occur.
CodePudding user response:
You can also add EXPECT_CALL in initialization of dummy variable:
class FooTest : ::testing::Test {
public:
FooTest() {}
~FooTest() = default;
protected:
void SetUp() override {}
void TearDown() override {}
MockUI m_ui;
bool dummy = (EXPECT_CALL(m_ui, get_name()), true);
Foo m_foo{m_ui};
};
I moved initialization of m_foo
, but it just for better visibility of order of initialization, you can left it in constructor.