EXPECT_CALL (макет, f (N)) против f (K), за которым следует f (N) - PullRequest
2 голосов
/ 14 мая 2019

Я пытаюсь понять, как работают EXPECT_CALLs, и я застрял со странным поведением (на мой взгляд, странным). Допустим, мой код делает это (предположим, что есть макет, а f (int) - это его метод, также давайте предположим, что SomeNiceMock - это NiceMock):

void SomeMock::f(int) { ... }
NiceMock<SomeMock> someNiceMock;
void runCycle(int n) { someNiceMock.f(n); }

Теперь, если в тесте я сделаю следующее

EXPECT_CALL(someNiceMock, f(2)).Times(AtLeast(1));
runCycle(1);
runCycle(2);
::testing::Mock::VerifyAndClearExpectations(&mock);

Я получаю ошибку, что f (int), как предполагалось, было вызвано с 2, но было вызвано с 1.

Expected: to be called at least once
Actual: never called - unsatisfied and active

Если я сделаю это так:

runCycle(1);
EXPECT_CALL(someNiceMock, f(2)).Times(AtLeast(1));
runCycle(2);
::testing::Mock::VerifyAndClearExpectations(&mock);

Все работает.

Я могу жить с таким поведением, я просто не понимаю причину этого. someNiceMock - это NiceMock, поэтому он не должен жаловаться на то, что f (int) вызывается с каким-то другим аргументом, тогда ожидаемым, если на самом деле был вызов f (int) с ожидаемым аргументом. Второй вызов runCycle (2) вызвал f (2). Так почему же вызов f (1) не был просто проигнорирован и проверка не прошла? Это так, что если я укажу EXPECT_CALL даже для NiceMock, если этот вызов будет с другим аргументом (но позже будет другой вызов с правильным аргументом), тест провалится? Разве это не противоречит интуиции, учитывая, что это NiceMock, и вызов f (2) действительно произошел в обоих случаях?

РЕДАКТИРОВАТЬ : И как мне тогда проверить такое поведение? Допустим, у меня есть какой-то генератор чисел, и я хочу проверить, что при вызове 10 раз он возвращает 5, по крайней мере, 3 раза (и мне плевать на другие результаты. Я ожидал бы закодировать его так (извините, если я запутался синтаксис, я не так хорош в издевательстве над Google):

struct INumberGeneratorSink {
    virtual void consumeNumber(int number) = 0;
};

struct NumberGeneratorSink : public INumberGeneratorSink  {
    void consumeNumber(int number) override { ... }
};

struct NumberGeneratorSinkMock : public INumberGeneratorSink  {
    MOCK_METHOD1(consumeNumber, void(int number));
};

void numberGeneratorFunction(INumberGeneratorSink &sink)
{
    for (int i = 0; i < 10; i++)
    {
        sink.consumeNumber(getNumberFromSomewhere());
    }       
}

NumberGeneratorSinkMock sinkMock;
NiceMock<NumberGeneratorSinkMock> niceSinkMock;

EXPECT_CALL(niceSinkMock, consumeNumber(5)).Times(AtLeast(3));
numberGeneratorFunction(niceSinkMock);

Как я могу кодировать подобные вещи? Если есть какая-то синтаксическая ошибка, пожалуйста, исправьте меня, но мой вопрос больше напоминает - если я забочусь только о том, чтобы потребление, номер 3 вызывался со значением 5, а меня не заботило остальное, как я могу его кодировать? Должен ли я написать что-то вроде:

// not sure about syntax for Any(),
// maybe it doesn't exist and has to be AtLeast(1)
EXPECT_CALL(niceSinkMock, consumeNumber(_)).Times(Any()); 
EXPECT_CALL(niceSinkMock, consumeNumber(5)).Times(AtLeast(3));

Будет ли это работать? Не будет ли первый EXPECT_CALL просто соответствовать всему, и тест будет пройден, даже если в качестве аргумента никогда не будет вызван статистически значимый параметр «5»?

1 Ответ

2 голосов
/ 17 мая 2019

Я полностью согласен, gmock может сбивать с толку относительно ожиданий.; -)

1) Почему не получается следующее?

EXPECT_CALL(someNiceMock, f(2)).Times(AtLeast(1));
runCycle(1);
runCycle(2);

Если у ложного метода нет EXPECT_CALL, но он вызывается, Google Mock выведет предупреждение.Чтобы подавить это предупреждение, вы можете использовать NiceMock.Однако, если EXPECT_CALL существует, он будет и должен потерпеть неудачу.

2) Почему следующий проход?

runCycle(1);
EXPECT_CALL(someNiceMock, f(2)).Times(AtLeast(1));
runCycle(2);

Простой ответ: EXPECT_CALL должен быть написан раньше.Но такой способ написания тестов не должен быть обычным способом.

3) Решение, позволяющее справиться с множественными ожиданиями

Из поваренной книги gmock :

"По умолчанию при вызове фиктивного метода Google Mock будет искать ожидания в обратном порядке, в котором они определены, и останавливаться, когда будет найдено активное ожидание, соответствующее аргументам" *

Ваш последний взломанный код почти верен.Правильная реализация Times (Any ()) - опустить его.

EXPECT_CALL(someNiceMock, f(_));
EXPECT_CALL(someNiceMock, f(2)).Times(1);
runCycle(1);
runCycle(2);

Также обратите внимание, что вашему Mock "SomeMock" нужен метод "mocked".Например:

class SomeMock {
public:
  MOCK_CONST_METHOD1(f, void(int i));
};
...