首页 > 解决方案 > GoogleMock:如何保存要在模拟的下一次调用中使用的参数

问题描述

我尝试模拟代表 NVRAM 的现有类的行为和 API。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. 创建ClassUnderTest,也调用Init方法

  2. 在 my 中调用另一个方法ClassUnderTest,该方法调用Restore-method。而且我希望能够以某种方式控制我的模拟,即在调用Restore-method之后dataPointer设置的值。

或者在伪代码中:

MockFoo foo;
EXPECT_CALL(foo, Init(dataPointer)).WillOnce(Return(true));
EXPECT_CALL(foo, Restore()).WillOnce(DoAll(memcpy(dataPointer, testValues, sizeOf(testValues)), Return(true)));

到目前为止我已经尝试过:

最后对我来说主要问题是:有没有办法在 -calldataPointer期间保存Init以供以后使用?

标签: c++unit-testinggooglemock

解决方案


SaveArg就我个人而言,我几乎从不使用 thisACTION或其他小的 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 负责操作它。无论如何,这应该可以解决您的问题。


推荐阅读