【问题标题】:C++ Google Mock SaveArg : how to save a pointer argumentC++ Google Mock SaveArg:如何保存指针参数
【发布时间】:2014-09-17 12:00:16
【问题描述】:

我很难保存我的模拟接收到的指针参数。

#define SIZE_OF_DATA

typedef struct {
    uint32_t someValue1;
    uint16_t someValue2;
    // other values here
} LargeStruct;


class SomeClass {
public:
    // assume sendData is a generic function where data is actually pointer to a LargeStruct
    void sendData(const uint8_t* data, const uint16_t size);
}

class MockClass : public SomeClass {
public:
    MOCK_METHOD2(sendData, void(const uint8_t*, const uint16_t));
};

我想将第一个参数保存到sendData(指针)并查看它指向的数据(它指向一个很大的结构,所以我不想按值复制):

TEST(SomeFixture, sendData_checkSentDataIsValid) {
   MockClass mock;

  const uint8_t *pData;
  EXPECT_CALL(mock, sendData(_, SIZE_OF_DATA)).WillOnce(SaveArg<0>(&pData));

  // do something here that calls sendData()

  // hopefully data should point to the same data that was passed in to the method
  LargeStruct *ls = (LargeStruct *)pData;

  // now verify that the data is ok...
  // some expectations here
  EXPECT_EQ(SOMEVALUEIWANT, ls->someValue1); 

}

但是,pData 指向的数据是错误的——我想我似乎是将指针值保存到结构中,而不是保存指针。

我认为问题在于我传递给 SaveArg 的变量,但我似乎无法在编译并给出正确答案的版本中得到它。请大家指点一下?

【问题讨论】:

    标签: c++ googlemock


    【解决方案1】:

    我刚刚遇到了同样的情况,在我的例子中,我必须确保传递给你的 sendData() 函数的指针没有指向堆栈上的自动变量。否则,当您访问指针时,内容将发生变化。我发现这没什么用,所以我决定定义一个自定义的 SaveArg 替代方案,如下所示:

    ACTION_TEMPLATE(SaveSomeValue1,
                    HAS_1_TEMPLATE_PARAMS(int, k),
                    AND_1_VALUE_PARAMS(pointer))
    {
        const void * data = ::std::tr1::get<k>(args);
        const LargeStruct* ls = (const LargeStruct *)data;
        *pointer = ls->someValue1;
    }
    

    然后你可以像这样使用它:

    uint32_t someValue1;
    EXPECT_CALL(mock, sendData(_, SIZE_OF_DATA))
        .WillOnce(SaveSomeValue1<0>(&someValue1));
    //...
    EXPECT_EQ(SOMEVALUEIWANT, someValue1);
    

    【讨论】:

    • 我目前看到此解决方案出现编译器错误 (MSVS 2017),表明操作“必须返回一个值”。我在语句块的末尾添加了一个return 0;,这解决了问题,允许编译,但安全吗? (GMock 1.7.0)
    • 跟进我自己的评论:“必须返回一个值”意味着该操作应返回与被模拟的函数相同的类型值。使用@dalestewart 的技术或默认的SaveArg() 操作,需要DoAll() 操作将副作用操作(返回void)与显式Return() 操作链接起来。
    【解决方案2】:

    您可以创建一个 void 指针作为缓冲区并将参数保存在该缓冲区中。之后,您应该将缓冲区转换为大型结构。

     TEST(SomeFixture, sendData_checkSentDataIsValid) {
      MockClass mock;
      LargeStruct *ls;
      void *buffer;
    
      EXPECT_CALL(mock, sendData(_, SIZE_OF_DATA))
                 .WillOnce(SaveArg<0>(&buffer));
    
     // do something here that calls sendData()
    
      ls = static_cast<LargeStruct  *>(buffer);
    
      EXPECT_EQ(SOMEVALUEIWANT, ls->someValue1); 
    
    }
    

    【讨论】:

    • 如果将sendData作为参数获取的LargeStruct数据分配在栈上,那么由SaveArg填充的void *缓冲区会指向sendData返回后释放的内存吗?
    猜你喜欢
    • 1970-01-01
    • 2011-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-01
    • 1970-01-01
    相关资源
    最近更新 更多