GoogleMock: как сохранить параметр для использования при следующем вызове макета - PullRequest
2 голосов
/ 11 июня 2019

Я пытаюсь смоделировать поведение и 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

Мой тестовый сценарий выглядит следующим образом:

  1. Create ClassUnderTest, также вызывает метод Init

  2. Вызовите другой метод в моем 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)));

То, что я пробовал до сих пор:

  • Действия по умолчанию из googleMock (например, SaveArg): позволяет мне записывать данные в dataPointer, но толькоa Init -call.
  • Запись ACTION_TEMPLATE для сохранения dataPointer в переменной lokal и изменения ее значения при вызове Restore: насколько я понимаю, я могу добавить только VALUE_PARAMSв ACTION_TEMPLATE, чтобы я мог передать значения в шаблон, но у меня нет возможности снова передать их по какому-либо указателю.
  • Я посмотрел на ActionInterface & Polymorphic Actions, если я правильно понимаю документацию, они имеют те же ограничениякак ACTION_TEMPLATE, относительно моей проблемы.

В конце концов, главный вопрос для меня: есть ли способ сохранить dataPointer во время Init -вызова для использования позже?

1 Ответ

2 голосов
/ 11 июня 2019

Лично я почти никогда не использую эту 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 отвечает за ее манипулирование.В любом случае это должно решить вашу проблему.

...