Я не понимаю следующий пример gmock:
{
InSequence s;
for (int i = 1; i <= n; i++) {
EXPECT_CALL(turtle, GetX())
.WillOnce(Return(10*i))
.RetiresOnSaturation();
}
}
Когда я удаляю .RetiresOnSaturation (), приведенный выше код работает так же - GetX возвращает 10, 20 и так далее. В чем причина использования .RetiresOnSaturation (), когда мы также используем объект В последовательности? Не могли бы вы это объяснить?
В данном конкретном примере RetiresOnSaturation()
ничего не меняет. Когда последнее ожидание в последовательности насыщается, оно остается активным, но насыщенным. Дальнейший вызов приведет к сбою теста.
RetiresOnSaturation()
обычно используется при наложении ожиданий. Например:
class Turtle {
public:
virtual int GetX() = 0;
};
class MockTurtle : public Turtle {
public:
MOCK_METHOD0(GetX, int());
};
TEST(GmockStackoverflow, QuestionA)
{
MockTurtle turtle;
// General expectation - Perhaps set on the fixture class?
EXPECT_CALL(turtle, GetX()).WillOnce(Return(0));
// Extra expectation
EXPECT_CALL(turtle, GetX()).WillOnce(Return(10)).RetiresOnSaturation();
turtle.GetX();
turtle.GetX();
}
Это свойство можно использовать в сочетании с InSequence
, когда последовательность ожидаемых событий перекрывает другое ожидание. В этом сценарии последнее ожидание в последовательности должно быть помечено как RetiresOnSaturation()
. Обратите внимание, что нужно отмечать только последнее ожидание, потому что, когда ожидание в последовательности насыщается, оно отменяет предварительные ожидания.
Пример ниже демонстрирует, как это может работать на практике. Удаление RetiresOnSaturation()
приводит к сбою теста.
TEST(GmockStackoverflow, QuestionB)
{
MockTurtle turtle;
EXPECT_CALL(turtle, GetX()).WillOnce(Return(0));
{
InSequence s;
EXPECT_CALL(turtle, GetX()).WillOnce(Return(10));
EXPECT_CALL(turtle, GetX()).WillOnce(Return(10)).RetiresOnSaturation();
}
turtle.GetX();
turtle.GetX();
turtle.GetX();
}
По моему опыту, некоторые (хорошо, возможно, многие) разработчики сталкиваются с проблемой, такой как сообщение об ошибке gtest, обнаруживают, что RetiresOnSaturation()
устраняет проблему, и затем приобретают привычку щедро разбрызгивать RetiresOnSaturation()
на протяжении своих модульных тестов - потому что это решает проблемы. . Это, по-видимому, проще, чем рассуждать о том, что должен выполнять тестовый пример. С другой стороны, мне нравится думать о том, что должно произойти (согласно контракту API задокументированный), в каком порядке - который может быть частичным, если вы используете After()
или не все в той же последовательности - и что делает более выразительные конструкции вроде InSequence
или After()
естественно приходить мне в голову.
Итак, как заявил Адам Кейси, нет никаких технических причин, но ИМО может быть проблема магического мышления или недостаточной подготовки.
Я рекомендую избегать RetiresOnSaturation()
. С ним есть некоторые общие проблемы (например, вызывающие запутанные предупреждающие сообщения, см. Пример ниже), но в основном это слишком низкий уровень по сравнению с альтернативами и почти никогда не требуется, если у вас есть чистые контракты и правильно используете ранее упомянутые альтернативы. . Можно сказать, что это goto
самых высоких ожиданий ...
Приложение A: Пример, когда безвозмездный RetiresOnSaturation()
ухудшает качество сообщений, и да, я видел такой код:
EXPECT_CALL(x, foo()).WillOnce(Return(42)).RetiresOnSaturation();
Если x.foo()
вызывается более одного раза, скажем, дважды, то без RetiresOnSaturation()
вы бы получили сообщение об ошибке типа «Нет соответствия ожиданиям для foo ()… Ожидается: вызывается один раз… Фактически: вызывается дважды (перенасыщено)», который как можно более конкретен. Но из-за RetiresOnSaturation()
вы получите только предупреждение «Неожиданный вызов функции foo ()», которое сбивает с толку и бессмысленно.
Приложение B: В вашем примере также возможно, что рефакторинг для использования InSequence
был произведен постфактум, и человек, выполняющий рефакторинг, не осознавал, что RetiresOnSaturation()
теперь является избыточным. Вы можете сделать "виноватым" в своей системе контроля версий, чтобы проверить.
Я думаю, что это была проблема копирования и вставки, когда автор забыл отредактировать второй пример, потому что он работал при запуске.