Есть несколько подходов, которые могут работать для вас. Мне нравится решение с Invoke
в качестве действия по умолчанию, потому что оно наиболее гибкое. Вы не указали mcve в своем вопросе, поэтому я написал очень простые реализации для используемых вами классов. Также вы допустили ошибку, используя unique_ptr
для макета. В 99% случаев это должно быть shared_ptr
, поскольку вы делите его между средой тестирования и тестируемой системой.
class Msg {};
class Handler {
public:
virtual bool RxMsg(Msg &msg) = 0;
};
class MockHandler: public Handler
{
public:
MOCK_METHOD1(RxMsg, bool(Msg &msg));
};
class Dispatcher {
public:
Dispatcher(std::shared_ptr<Handler> handler): h_(handler) {}
void run() {
Msg m;
std::cout << h_->RxMsg(m) << std::endl;
}
private:
std::shared_ptr<Handler> h_;
};
class MyFixture: public ::testing::Test {
protected:
MyFixture(): mockCallCounter_(0) {
mockHandler_.reset(new MockHandler);
sut_.reset(new Dispatcher(mockHandler_));
}
void configureMock(int period) {
ON_CALL(*mockHandler_, RxMsg(_)).WillByDefault(Invoke(
[this, period](Msg &msg) {
// you can also set the output arg here
// msg = something;
if ((mockCallCounter_++ % period) == 0) {
return true;
}
return false;
}));
}
int mockCallCounter_;
std::shared_ptr<MockHandler> mockHandler_;
std::unique_ptr<Dispatcher> sut_;
};
TEST_F(MyFixture, HandlePing) {
configureMock(10);
for (int i = 0; i < 199; i++) {
sut_->run();
}
}
В начале каждого теста вы должны вызывать метод configureMock
, который будет вызывать макрос ON_CALL
, устанавливающий действие по умолчанию для вашего макета. Функция, переданная в Invoke
, может быть любой функцией, соответствующей сигнатуре перезаписываемого метода. В этом случае это функция, которая подсчитывает, сколько раз mock уже был вызван и возвращает соответствующее значение. Вы также можете назначить некоторый конкретный объект выходному аргументу msg
.