You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 04:35:20