Home > Back-end >  How to call EXPECT_CALL gtest macro before the object construction
How to call EXPECT_CALL gtest macro before the object construction

Time:11-21

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.

  • Related