protobuf通過反射來賦值
阿新 • • 發佈:2018-12-22
最近因為專案邏輯方面都做的差不多了,於是趕緊去做做測試工作,免得專案上線之後出問題,於是打算用配置的形式做一個類似與白盒測試工具的東西出來。
因為專案使用pb來做協議通訊,所以配置的xml也是類似於pb,將pb的欄位和型別配置進去,然後加上值,一個協議結構就可以了,現在只能通過修改值來做測試,後面會改動的更智慧化一些,例如某個行為的次數,某個行為更隨機等等。
去讀了一下陳碩的關於pb處理協議的反射,學到了不少東西,同時對pb的一些東西理解更深刻了,google還是大牛很多。
1.如何處理pb的反射,通過協議字串動態生成一個協議
pb提供了一個強大的DescriptorPool::generated_pool()
程式碼如下:
inline google::protobuf::Message* CreateMessage(const std::string& msg) { google::protobuf::Message* message = NULL; const google::protobuf::Descriptor* descriptor = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("ProtoMsg." + msg); if (descriptor) { const google::protobuf::Message* prototype = google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor); if (prototype) { message = prototype->New(); } } return message; } inline void ReleaseMessage(google::protobuf::Message* pMsg) { if (NULL != pMsg) { pMsg->Clear(); delete pMsg; } }
這兩個函式可以動態生成pb的message,其中ProtoMsg是你pb package的名字
2.通過反射將配置中的值設定進pb欄位
pb的Message基類提供了一個Reflection,這個類非常強大
程式碼如下
// mstrCurMsg 當前正在執行的協議 google::protobuf::Message* pMsg = Test::CreateMessage(mstrCurMsg); const google::protobuf::Descriptor* pDescriptor = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("ProtoMsg." + mstrCurMsg); assert(NULL != pDescriptor); // 這一個可以獲取到反射類,然後可以將配置中值賦值進去 const google::protobuf::Reflection* pReflection = pMsg->GetReflection(); assert(NULL != pReflection); for (int i = 0; i < pDescriptor->field_count(); ++i) { const google::protobuf::FieldDescriptor* pFieldDescriptor = pDescriptor->field(i); assert(NULL != pFieldDescriptor); const std::string& strFieldName = pFieldDescriptor->name(); const TestConfigModule::MsgEntry* pMsgEntry = pMsgStruct->GetMsgEntry(strFieldName); assert(NULL != pMsgEntry); // 讀取欄位型別,順帶可以做型別檢查 assert(pMsgEntry->mnType == pFieldDescriptor->type()); // 設定值 switch (pMsgEntry->mnType) { case Test::TYPE_STRING: pReflection->SetString(pMsg, pFieldDescriptor, pMsgEntry->mstrValue); break; // ... default: break; } } std::string strData; if (!pMsg->SerializeToString(&strData)) { m_pLogModule->LogNormal("Test stop, cannot SerializeToString ", mstrCurMsg, __FUNCTION__, __LINE__); return; } Test::ReleaseMessage(pMsg);
通過這樣的步驟,就可以自動建立message和對field賦值了,如果你也有pb的使用經驗和技巧,歡迎分享