Search code examples
c++googletestgooglemock

How to call EXPECT_CALL gtest macro before the object construction


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?


Solution

  • 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;
    };