如何编写Google Mock匹配器以匹配void指针参数?
GMock匹配const void*参数的解决方案
问题描述
需要Mock一个接收const void*类型参数的函数,希望基于传入指针指向的值编写匹配器,但直接指针比较无效(因为调用时传递的是循环变量的地址,和测试代码中的变量地址不同)。尝试使用SaveArgPointee时报错const void* is not a pointer-to-oject type,自定义Action也因类型转换问题无法实现。
示例代码
#include <vector> #include "gmock/gmock.h" #include "gtest/gtest.h" class A { public: A(std::vector<uint32_t> data) : m_data(data) {} void doSomething() { // 注意:原代码中这里用了data,应该改为m_data for (auto x : m_data) writeData(&x, sizeof(x)); } void writeData(const void* val, size_t size) { // 实际逻辑更复杂 std::cout << "Writing data" << std::endl; } private: std::vector<uint32_t> m_data; }; class MockA : public A { public: MOCK_METHOD(void, writeData, (const void* val, size_t size)); }; // 原代码缺少分号 TEST(TestA, writeData) { std::vector<uint32_t> testData{1,2,3,4}; MockA myMockObj(testData); uint32_t expVal1 = 1; uint32_t expVal2 = 2; uint32_t expVal3 = 3; uint32_t expVal4 = 4; // 问题:writeData接收const void*,指针比较无效,因为地址不同 // 例如&testData[1] != m_data[1],(void*)&expVal2 != val EXPECT_CALL(myMockObj, writeData(expVal4, 4)).Times(1); EXPECT_CALL(myMockObj, writeData(expVal3, 4)).Times(1); EXPECT_CALL(myMockObj, writeData(expVal2, 4)).Times(1); EXPECT_CALL(myMockObj, writeData(expVal1, 4)).Times(1); myMockObj.doSomething(); }
解决方案
核心是通过自定义GMock匹配器,将const void*安全转换为目标类型后比较指向的值,同时验证size参数的正确性。
方案1:自定义双参数匹配器(同时验证指针值和size)
使用MATCHER_P2宏创建匹配器,同时接收预期值和预期size,打包两个参数进行匹配:
// 自定义匹配器:验证const void*指向的uint32_t值,以及size参数 MATCHER_P2(MatchVoidPtrToUint32, expectedVal, expectedSize, "") { // 先校验size是否符合预期,同时确保size是uint32_t的大小,避免错误转换 if (arg.second != expectedSize || expectedSize != sizeof(uint32_t)) { return false; } // 将void*转换为uint32_t指针,取值比较 const uint32_t* actualVal = static_cast<const uint32_t*>(arg.first); return *actualVal == expectedVal; }
修改测试中的EXPECT_CALL,用_匹配任意参数,然后通过WillOnce指定匹配逻辑:
TEST(TestA, writeData) { std::vector<uint32_t> testData{1,2,3,4}; MockA myMockObj(testData); uint32_t expVal1 = 1; uint32_t expVal2 = 2; uint32_t expVal3 = 3; uint32_t expVal4 = 4; const size_t uint32Size = sizeof(uint32_t); EXPECT_CALL(myMockObj, writeData(_, _)) .WillOnce(MatchVoidPtrToUint32(expVal1, uint32Size)) .WillOnce(MatchVoidPtrToUint32(expVal2, uint32Size)) .WillOnce(MatchVoidPtrToUint32(expVal3, uint32Size)) .WillOnce(MatchVoidPtrToUint32(expVal4, uint32Size)); myMockObj.doSomething(); }
方案2:单参数匹配器组合(分别验证每个参数)
先创建仅验证const void*指向值的匹配器,再和size的精确匹配组合使用:
// 自定义匹配器:验证const void*指向的uint32_t值 MATCHER_P(MatchVoidPtrToUint32Val, expectedVal, "") { // 这里默认调用方已经保证size正确,或者可以在外部配合size匹配器 const uint32_t* actualVal = static_cast<const uint32_t*>(arg); return *actualVal == expectedVal; }
修改EXPECT_CALL,组合两个匹配器:
TEST(TestA, writeData) { std::vector<uint32_t> testData{1,2,3,4}; MockA myMockObj(testData); uint32_t expVal1 = 1; uint32_t expVal2 = 2; uint32_t expVal3 = 3; uint32_t expVal4 = 4; const size_t uint32Size = sizeof(uint32_t); EXPECT_CALL(myMockObj, writeData(MatchVoidPtrToUint32Val(expVal1), uint32Size)).Times(1); EXPECT_CALL(myMockObj, writeData(MatchVoidPtrToUint32Val(expVal2), uint32Size)).Times(1); EXPECT_CALL(myMockObj, writeData(MatchVoidPtrToUint32Val(expVal3), uint32Size)).Times(1); EXPECT_CALL(myMockObj, writeData(MatchVoidPtrToUint32Val(expVal4), uint32Size)).Times(1); myMockObj.doSomething(); }
注意事项
- 确保
const void*指向的确实是目标类型(这里是uint32_t),否则类型转换会导致未定义行为,建议在匹配器中加入size校验(如方案1)。 - 原示例代码中的两处编译错误需修正:
doSomething中遍历的是m_data而非构造函数参数data,MockA类定义末尾缺少分号。
内容的提问来源于stack exchange,提问作者ventsyv
相关产品推荐
相关产品推荐

