gtest中SetArgPointee赋值异常:uint转uint8_t转换错误排查
gmock中SetArgPointee设置大值异常的原因及解决方法
问题背景
我定义了Bar类,它持有Foo类的引用,Foo类包含read方法。我使用gtest对Bar类的公有方法Bar::test()进行单元测试,该方法会根据通过Foo对象读取的unsigned int值执行不同逻辑。
目前遇到的问题是:用SetArgPointee设置值为50时测试正常,但设置为666时测试异常。看起来像是unsigned int到uint8_t的转换错误,但无法明确原因,希望理清认知误区。
示例代码
#include <gtest/gtest.h> #include <gmock/gmock.h> struct Foo { MOCK_METHOD(bool, read, (uint8_t* p_data_dst, const std::size_t p_size, std::size_t offset), (const)); }; class Bar { public: Bar(Foo& foo) : m_foo(foo) { }; Foo& m_foo; bool test() { unsigned int value = 0; m_foo.read(reinterpret_cast<std::uint8_t*>(&value), sizeof(unsigned int), 0); if (value == 666) { return true; } return false; } }; TEST(StackOverflow, Exemple) { Foo foo; Bar bar(foo); unsigned int val = 666; EXPECT_CALL(foo, read(testing::_, sizeof(unsigned int), 0)).WillOnce(testing::DoAll(testing::SetArgPointee<0>(val), testing::Return(true))); EXPECT_TRUE(bar.test()); }
问题根源
核心错误在于对SetArgPointee的理解偏差:
Foo::read的第一个参数是uint8_t*,SetArgPointee<0>(val)会将val(unsigned int类型)转换为uint8_t,然后只向目标地址写入一个字节。- 当
val=50时,50的二进制是0x32,可以完整放入uint8_t,写入unsigned int的第一个字节后,其余字节因初始化为0,整个value的值就是50,符合预期。 - 当
val=666时,666的二进制是0x29A,转换为uint8_t会截断为低8位0x9A(十进制154),写入后value的值变为0x0000009A(154),自然不等于666,导致test()返回false,测试失败。
解决方案
要完整写入unsigned int的所有字节,需要使用能处理连续内存的动作,比如SetArrayArgument或自定义Invoke动作:
方案1:使用SetArrayArgument
TEST(StackOverflow, Exemple) { Foo foo; Bar bar(foo); unsigned int val = 666; EXPECT_CALL(foo, read(testing::_, sizeof(unsigned int), 0)) .WillOnce(testing::DoAll( testing::SetArrayArgument<0>( reinterpret_cast<uint8_t*>(&val), reinterpret_cast<uint8_t*>(&val) + sizeof(unsigned int) ), testing::Return(true) )); EXPECT_TRUE(bar.test()); }
方案2:使用自定义Invoke动作(memcpy)
TEST(StackOverflow, Exemple) { Foo foo; Bar bar(foo); unsigned int val = 666; EXPECT_CALL(foo, read(testing::_, sizeof(unsigned int), 0)) .WillOnce(testing::DoAll( testing::Invoke([val](uint8_t* dst, std::size_t size, std::size_t) { memcpy(dst, &val, size); }), testing::Return(true) )); EXPECT_TRUE(bar.test()); }
内容的提问来源于stack exchange,提问作者LPo
相关产品推荐
相关产品推荐

