【问题标题】:GoogleMock: How to save a parameter to be used in the next call on the mockGoogleMock:如何保存要在模拟的下一次调用中使用的参数
【发布时间】:2019-06-11 12:21:49
【问题描述】:

我尝试模拟表示 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. 在我的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,但仅限于 Init 调用。
  • 编写 ACTION_TEMPLATE 以将 dataPointer 保存在 lokal 变量中,然后在调用 Restore 时更改其值: 据我了解,我只能将 VALUE_PARAMS 添加到 ACTION_TEMPLATE,因此我可以将值传递到模板中,但无法通过某个指针再次分发它们。
  • 我查看了 ActionInterface & Polymorphic Actions,如果我正确理解文档,它们与 ACTION_TEMPLATE 的限制相同,就我的问题而言。

最后,我的主要问题是: 有没有办法在 Init 调用期间保存 dataPointer 以供以后使用?

【问题讨论】:

    标签: c++ unit-testing googlemock


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多