我有一个在初始化列表中调用模拟函数的类。我想使用EXPECT_CALL来验证模拟函数只被调用一次。问题是我不能在构造函数之前使用宏,因为它是第一个运行的函数,也不能在它之后使用宏,因为在构造函数中调用了模拟函数。
例如: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));
};
问题出现在这里: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;
};
我尝试在SetUp()
函数中初始化Foo
对象,但Foo没有默认构造函数,因此必须在FooTest
构造函数中初始化。
解决方案?我唯一的想法是在MockUI构造函数中像这样调用EXPECT_CALL()
:mock_ui.hpp
class MockUI : public UI {
MockUI() : UI() {
EXPECT_CALL(*this, get_name());
}
~MockUI() = default;
MOCK_METHOD(std::string, get_name, (), (override);
};
问题是我可能使用MockUI而不调用get_name()
或多次调用它,但这是我拥有的最佳解决方案。
还有其他建议吗?
可以使用指针延迟Foo
的初始化:
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;
};
或者通过添加父类来首先初始化MockUI
:
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;
};
您还可以在初始化虚拟变量时添加EXPECT_CALL:
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};
};
我移动了m_foo
的初始化,但是为了更好地看到初始化的顺序,你可以把它留在构造函数中。