首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何与派生类的SaveArgPointee和std::shared_ptr一起使用gmock

如何与派生类的SaveArgPointee和std::shared_ptr一起使用gmock
EN

Stack Overflow用户
提问于 2021-11-30 16:39:00
回答 1查看 506关注 0票数 1

我有一个BaseMessage类,从中派生出几个不同的DerivedMessage子类,并希望这样发送它们:

代码语言:javascript
运行
复制
class BaseMessage {
public:
   virtual std::vector<uint8_t> data() const noexcept = 0;
   virtual ~BaseMessage() = default;
   [...]
}

class DerivedMessage : public BaseMessage {
public:
   [...]
   std::vector<uint8_t> data() const noexcept override { return m_data; }
private:
   std::vector<uint8_t> m_data;
}

// simplified 
class Tcp {
public
   virtual void sendMessage(std::shared_ptr<BaseMessage> msg) { write(msg->data());}
   [...]
};

class SomeClass {
public:
   SomeClass(Tcp& tcp) : m_tcp(tcp) {}
   void writeDataToRemote(std::shared_ptr<DerivedMessage> derived) const {
      m_tcp.sendMessage(derived);
private:
   Tcp m_tcp;
}
};

现在,我想用gtest为SomeClass编写测试。

因此,我模拟TCP类的功能:

代码语言:javascript
运行
复制
class MockTcp : public Tcp {
MOCK_METHOD(void, sendMessage, (std::shared_ptr<ralco::CommandMsg> msg), (override));
[...]
}

让我们假设,到目前为止,这一切都简化了,但仍然有效。

因此,在测试中,我想检查函数sendMessage中给writeDataToRemote的参数。我在::testing::SaveArg上读到了关于StackOverflow和::testing::SaveArgPointee的文章(但没有在文档中看到)。

代码语言:javascript
运行
复制
TEST(SomeClassTest, writesMessageToSocket){
   MockTcp mockTcp;
   SomeClass sc(mockTcp);
   
   // >>>how to declare msgArg here?<<<
   EXPECT_CALL(mockTcp, sendMessage(_)).Times(1).WillOnce(::testing::SaveArgPointee<0>(msgArg));
   const auto derivedMsg = std::make_shared<DerivedMessage>();
   sc.writeDataToRemote(derivedMsg);
   // further inspection of msgArg follows
}

正如代码注释中所写的那样,我不知道如何声明msgArg变量,以便将实际的参数分配给sendMessage。当使用SaveArg时,我想我会得到一个悬空指针,并且像上面那样做,我会得到错误,因为消息不能被复制分配。任何暗示都被接受了。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-30 17:06:27

在您的示例中,您实际上只想保存和检查已考虑的shared_ptr,因此使用SaveArg就足够了。

代码语言:javascript
运行
复制
    MockTcp mockTcp;
    SomeClass sc(mockTcp);
    std::shared_ptr<BaseMessage> bm;
    EXPECT_CALL(mockTcp, sendMessage(_)).Times(1).WillOnce(::testing::SaveArg<0>(&bm));  // it will effectively do bm = arg;
    const auto derivedMsg = std::make_shared<DerivedMessage>();
    sc.writeDataToRemote(derivedMsg);
    // verify that the argument that you captured is indeed pointing to the same message
    std::cout << derivedMsg.get() << std::endl;
    std::cout << bm.get() << std::endl;

SaveArgPointee的常见误解是,它将arg指向测试中的局部变量赋值,这在您的情况下可能不是一个好主意,因为它将调用消息的副本构造函数。

或者,我可以推荐使用Invoke。它是非常通用和易于使用的。例如,您可以像这样捕获所需的论点:

代码语言:javascript
运行
复制
    MockTcp mockTcp;
    SomeClass sc(mockTcp);
    std::shared_ptr<BaseMessage> bm;
    EXPECT_CALL(mockTcp, sendMessage(_)).Times(1).WillOnce(::testing::Invoke([&bm](auto arg) { bm = arg; }));
    const auto derivedMsg2 = std::make_shared<DerivedMessage>();
    sc.writeDataToRemote(derivedMsg2);
    std::cout << derivedMsg2.get() << std::endl;
    std::cout << bm.get() << std::endl;

或者使用指向BaseMessage的原始指针

代码语言:javascript
运行
复制
    BaseMessage* rawBm = nullptr;
    EXPECT_CALL(mockTcp, sendMessage(_)).Times(1).WillOnce(Invoke([&rawBm](auto arg) { rawBm = arg.get(); }));
    const auto derivedMsg2 = std::make_shared<DerivedMessage>();
    sc.writeDataToRemote(derivedMsg2);
    std::cout << derivedMsg2.get() << std::endl;
    std::cout << rawBm << std::endl;
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70172898

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档