Search code examples
c++unit-testinggoogletestgooglemock

gmock Multiple mock instances, but only one is effective


I would like to test a class (Controller) that manages a set of entities of a certain kind. Entities are created internally in this class because a factory would be an overkill here, so here is how I inject mocks into it:

class TestController : public Controller {
public:
    /* Mechanism for a mock injection */
    std::shared_ptr<IEntity> create_entity() override {
        return temp_entity;
    }

    /* Variable to hold the entity being injected */
    std::shared_ptr<IEntity> temp_entity;
};

Production code invokes create_entity() in the Controller class, which I overload here, and adds the result to a container. temp_entity is the way I supply my mocks and the test, where I supply two distinct mock instances, looks like this:

class MockEntity : public IEntity {
    MOCK_METHOD0(perform_operation, bool());
}

TEST(ControllerTest, TestFailure) {
    std::shared_ptr<TestController> controller = std::make_shared<TestController>();

    std::shared_ptr<MockEntity> entity1 = std::make_shared<MockEntity>();
    controller->temp_entity = entity1;
    controller->add_entity(); // This invokation fetches the result of create_entity()

    std::shared_ptr<MockEntity> entity2 = std::make_shared<MockEntity>();
    controller->temp_entity = entity2;
    controller->add_entity(); // This invokation fetches the result of create_entity()

    EXPECT_CALL(*entity1, perform_operation().WillOnce(::testing::Return(true));
    EXPECT_CALL(*entity2, perform_operation().WillOnce(::testing::Return(false));

    controller->run();
}

controller.run() only concurrently executes perform_operation() on each of the entities.

When the test is run, the function in the second expectation is called twice and the function in the first expectation is not run at all. I am sure that the controller operates on two distinct versions of an entity before executing run() function.

Is there a fundamental problem in what I am trying to do? How can I separate my expectations for these two mocks in a test? I tried creating two distinct mock classes with perform_operation() method being implemented in the mock body and when running the test in the debugger I still hit the method of one mock class twice.


Solution

  • The test looks correct and the way, how you inject the mocks into the system under test, is an absolutely reasonable method.

    I suppose, the critical issue is in your class under Test. I rebuild your Test with the following controller:

    class Controller {
    public:
        virtual std::shared_ptr<IEntity> create_entity() = 0;
    
        void add_entity() {
            auto entity = create_entity();
            entities.push_back(entity);
        }
    
        void run() {
            for(auto e : entities) {
                bool i =  e->perform_operation();
            }
        }
        std::vector<std::shared_ptr<IEntity> > entities;
    };
    

    With this class the test succeeded like expected.