我有一个BaseMessage
类,从中派生出几个不同的DerivedMessage
子类,并希望这样发送它们:
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类的功能:
class MockTcp : public Tcp {
MOCK_METHOD(void, sendMessage, (std::shared_ptr<ralco::CommandMsg> msg), (override));
[...]
}
让我们假设,到目前为止,这一切都简化了,但仍然有效。
因此,在测试中,我想检查函数sendMessage
中给writeDataToRemote
的参数。我在::testing::SaveArg
上读到了关于StackOverflow和::testing::SaveArgPointee
的文章(但没有在文档中看到)。
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
时,我想我会得到一个悬空指针,并且像上面那样做,我会得到错误,因为消息不能被复制分配。任何暗示都被接受了。
发布于 2021-11-30 17:06:27
在您的示例中,您实际上只想保存和检查已考虑的shared_ptr
,因此使用SaveArg
就足够了。
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
。它是非常通用和易于使用的。例如,您可以像这样捕获所需的论点:
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
的原始指针
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;
https://stackoverflow.com/questions/70172898
复制相似问题