Gmock ожидает только конкретного вызова

У меня есть класс С++, который я пытаюсь протестировать с помощью GMock. У меня есть следующий фиктивный класс:

class MyTestMock
{
    public:
        MOCK_METHOD1(myCoolMethod, int(const char*));
        MOCK_METHOD1(myCoolMethod, int(string));
}

Затем в моем тесте происходит следующее:

MyTestMock myMock;
if ( myMock.myCoolMethod("stuff") )
{
    // Stuff I don't care about, don't want to execute
}
if ( myMock.myCoolMethod("moarStuff") )
{
    // More stuff I don't care about, don't want to execute
}
if ( myMock.myCoolMethod("foo") )
{
    // This I care about and want to execute
}

Что я хотел бы сделать, так это позволить первым двум вызовам быть неинтересными вызовами, которые возвращают значение по умолчанию для целых чисел, 0, в то время как я установил конкретное ожидание для третьего вызова, чтобы он возвращал 1. Это была моя попытка сделать это:

EXPECT_CALL(myMock, myCoolMethod(TypedEq<const char *>("foo"))).WillOnce(Return(1));

Однако это приводит к провалу теста. Если я сделаю это вместо этого:

EXPECT_CALL(myMock, myCoolMethod(Matcher<const char *>(_))).WillRepeatedly(Return(0));
EXPECT_CALL(myMock, myCoolMethod(TypedEq<const char *>("foo"))).WillOnce(Return(1));

мой тест проходит нормально. Я пытаюсь сделать модульное тестирование как можно более безболезненным на старой массивной кодовой базе монолитного стиля, поэтому мне бы очень хотелось, чтобы дополнительная волшебная строка не требовала возврата значения по умолчанию. Любые идеи о том, как я могу сделать это только с одним ожиданием, не проваливая тест?


person Dustin Wilhelmi    schedule 27.10.2015    source источник


Ответы (1)


Я предполагаю, что мой ответ не очень «ожидается» для тестирования «старой массивной кодовой базы монолитного стиля» с возможным огромным количеством таких CoolMethods..., но, к сожалению, именно так работает google-mock. Как вы можете прочитать в их FAQ:

Наличие ON_CALL в установочной части теста не означает, что звонки ожидаются. Если EXPECT_CALL отсутствует, а метод вызывается, возможно, это ошибка. Если мы спокойно пропустим вызов, не уведомляя пользователя, баги могут прокрасться незаметно.

То же самое и с "по умолчанию" ON_CALL - я имею в виду, когда вы не написали явно ON_CALL, потому что значение по умолчанию для типа (в вашем случае 0 для int) совершенно нормально.

Мой совет — всегда помещайте такое общее ожидание в SetUp функцию вашего набора тестов — таким образом ваши тестовые примеры не будут перегружены множеством магических ожиданий:

class MyTestSuite : public ::testing::Test
{
protected:
    MyTestMock myMock;
    void SetUp() override
    {
        EXPECT_CALL(myMock, myCoolMethod(Matcher<const char *>(_))).WillRepeatedly(Return(0));
    }   
};

Таким образом, у вас есть «раздражающие» строки только в одном месте, а ваши тестовые примеры «чисты»:

TEST_F(MyTestSuite, shallDoSomethingWhenCoolMethodAcceptsFoo)
{
   EXPECT_CALL(myMock, myCoolMethod(TypedEq<const char *>("foo"))).WillOnce(Return(1));
}
TEST_F(MyTestSuite, shallDoSomethingElseWhenCoolMethodAcceptsMoarStuff)
{
   EXPECT_CALL(myMock, myCoolMethod(TypedEq<const char *>("moarStuff"))).WillOnce(Return(1));
}
person PiotrNycz    schedule 27.10.2015
comment
Дело в том, однако, что это прекрасно работает, если я вообще не устанавливаю никаких ожиданий. Ошибка не в том, что он вызывается без ожидания, а в том, что он вызывается больше раз, чем указано ожидание, хотя мое ожидание ограничивало его TypedEq. - person Dustin Wilhelmi; 28.10.2015
comment
Хорошей практикой является всегда обертывать Mock StrictMock<MyTestMock> или NiceMock<MyTestMock>. В вашем случае я бы использовал StrictMock, так как вам интересно, как ведет себя этот макет. NiceMock предназначены для макетов, которые требуются для вашего тестируемого кода, но вы на самом деле не используете их в своих тестах. Ваш случай немного сложнее, потому что в некоторых аспектах это должен быть StrictMock (для вызова с помощью foo), в других — NiceMock. Такой дуализм решается путем указания этих общих ожиданий для аспектов NiceMock вашего макета. - person PiotrNycz; 28.10.2015