Я пытаюсь смоделировать поведение и API уже существующего класса, представляющего NVRAM. API:
bool Init(Uint8* dataPointer);
bool Store(); //Writes the data from dataPointer into the NVRAM
bool Restore(); //Writes the data from NVRAM into the dataPointer
Мой тестовый сценарий следующий:
Создать ClassUnderTest
, также вызывает метод Init
Вызов другого метода в моем ClassUnderTest
, который вызывает Restore
-метод. И я хочу иметь возможность управлять своим макетом таким образом, чтобы после вызова метода Restore
было установлено значение dataPointer
.
Или в псевдокоде:
MockFoo foo;
EXPECT_CALL(foo, Init(dataPointer)).WillOnce(Return(true));
EXPECT_CALL(foo, Restore()).WillOnce(DoAll(memcpy(dataPointer, testValues, sizeOf(testValues)), Return(true)));
Что я пробовал до сих пор:
dataPointer
, но только Init
-вызов.dataPointer
в локальной переменной и последующего изменения его значения при вызове Restore
: Насколько я понимаю, я могу добавить только VALUE_PARAMS в ACTION_TEMPLATE, поэтому я могу передать значения в шаблон, но не могу передать их снова по некоторому указателю.В итоге главный вопрос для меня:
Есть ли способ сохранить dataPointer
во время Init
-звонка, чтобы использовать его позже?
Лично я почти никогда не использую эти SaveArg
, ACTION
или другие мелкие функции gmock. Я предпочитаю использовать Invoke
и просто определять свою собственную логику, которая должна вызываться всякий раз, когда выполняется вызов фиктивного метода. Это может показаться излишеством, но на самом деле очень часто оно читабельнее и короче:
class API {
public:
virtual bool Init(uint8_t* dataPointer) = 0;
virtual bool Store() = 0;
virtual bool Restore() = 0;
};
class MockAPI : public API {
public:
MOCK_METHOD1(Init,
bool(uint8_t* dataPointer));
MOCK_METHOD0(Store,
bool());
MOCK_METHOD0(Restore,
bool());
};
class ClassUnderTest {
public:
explicit ClassUnderTest(std::shared_ptr<API> api): api_(api) {
dataPtr_ = new uint8_t;
api_->Init(dataPtr_);
}
~ClassUnderTest() {
delete dataPtr_;
}
bool anotherMethod() {
api_->Restore();
return true;
}
uint8_t takeALookAtTheData() {
return *dataPtr_;
}
private:
std::shared_ptr<API> api_;
uint8_t* dataPtr_;
};
using testing::_;
using testing::Invoke;
TEST(xxx, yyy) {
auto mockApi = std::make_shared<MockAPI>();
uint8_t* dataPtr(nullptr);
uint8_t testValue = 123;
ON_CALL(*mockApi, Init(_)).WillByDefault(Invoke([&dataPtr](uint8_t* dataPointer) {
dataPtr = dataPointer;
return true;
}));
ON_CALL(*mockApi, Restore()).WillByDefault(Invoke([&dataPtr, testValue]() {
*dataPtr = testValue;
return true;
}));
ClassUnderTest sut(mockApi);
ASSERT_NE(nullptr, dataPtr);
sut.anotherMethod();
ASSERT_EQ(testValue, *dataPtr);
ASSERT_EQ(testValue, sut.takeALookAtTheData());
}
Надеюсь, я правильно предположил, что ваша система должна выделять необходимую память, а ваш API отвечает за управление ею. В любом случае, это должно решить вашу проблему.