【问题标题】:Force googletest signed vs unsigned comparison to fail强制 googletest 签名与未签名比较失败
【发布时间】:2026-01-17 06:05:01
【问题描述】:

首先,我是 googletest 框架的新手,所以请善待。

我有一个函数

void setID(const int id)
{
    ID = id;
}

其中 ID 是全局 unsigned int。 (是的,全局变量很糟糕,我只是想弄清楚我在做什么。)

我的单元测试是这样的

TEST_F(TempTests, SetId)
{
    // Arrange
    int id = -99;

    // Act
    setId(id);

    // Assert
    EXPECT_EQ(id, ID);
}

问题是我的单元测试总是通过,我需要它失败,因为 ID 应该是有符号整数而不是无符号整数。如果我没有在视觉上发现错误,那么单元测试就会通过,并且以后可能会导致错误。

为确保将来不会发生这种情况,最好在这种情况下单元测试比较失败。

我尝试过以各种方式将idID 静态转换为有符号和无符号整数。 我尝试过EXPECT_TRUE(id == ID) 以各种方式将变量静态转换为有符号和无符号整数。 但在所有这些情况下,结果都是通过测试。

那么我怎样才能让 gtest 比较 id 的有符号值和 ID 的无符号值,以便测试失败,因为 id 将是 -99 而ID 将是 4294967197?

【问题讨论】:

  • 为什么不直接检查id 是否低于0?
  • 我不明白你的问题。这如何解决ID 的值是什么?
  • 如何添加额外的期望来检查两种类型是有符号还是无符号(通过使用 type_traits、decltype 或模板)?
  • 好主意,我会调查一下
  • 打开编译器警告,警告有符号值与无符号值的比较。将警告视为错误,并修复代码。

标签: c++ googletest


【解决方案1】:

所以我不知道如何表扬,但我最终结合使用了 inetknght 和 mkk 的建议。

TEST_F(TempTests, SetId)
{
    // Arrange
    int id = -99;

    // Act
    setId(id);

   // Assert
   EXPECT_TRUE(std::numeric_limits<decltype(id)>::is_signed == std::numeric_limits<decltype(ID)>::is_signed);
   EXPECT_EQ(id, ID);
}

根据inetknght 的建议,通过检查签名类型,我可以通过测试,因为这些类型都没有签名。并且根据 mkk 的建议,通过使用 decltype,我可以在将来更正 ID 类型时获得变量的声明类型,而无需修改单元测试。更正 ID 类型后,测试通过。

编辑

根据 Adrian McCarthy 的建议,我还在编译器标志中添加了 -Werror=conversion。

【讨论】:

    【解决方案2】:

    编译器需要将类型转换为相等。我推荐阅读this related answer

    您也许可以创建一个自定义的 googletest 比较器。即使没有,您至少可以使用类似的东西:

    #include <iostream>
    #include <cstdint>
    #include <limits>
    #include <type_traits>
    #include <typeinfo>
    
    template <class T>
    class SignedUnsignedIntCompare final /* final for non-virtual dtor, remember to make dtor virtual if you need to inherit */ {
    public:
        const T & v;
        SignedUnsignedIntCompare(const T & v) : v(v) {}
        SignedUnsignedIntCompare(SignedUnsignedIntCompare && move_ctor) = default;
        SignedUnsignedIntCompare(const SignedUnsignedIntCompare & copy_ctor) = default;
        SignedUnsignedIntCompare & operator=(SignedUnsignedIntCompare && move_assign) = default;
        SignedUnsignedIntCompare & operator=(const SignedUnsignedIntCompare & copy_assign) = default;
        ~SignedUnsignedIntCompare() = default;
    
        template <class TT>
        bool operator==(const TT & i) const {
            if ( std::numeric_limits<T>::is_signed != std::numeric_limits<TT>::is_signed ) {
                return ((v == i) && (T(v) <= std::numeric_limits<TT>::max()) && (TT(i) <= std::numeric_limits<T>::max()));
            }
            return (v == i);
        }
    };
    
    typedef SignedUnsignedIntCompare<int> SignedIntCompare;
    typedef SignedUnsignedIntCompare<unsigned> UnsignedIntCompare;
    
    int main() {
        int i = -99;
        unsigned int u = i;
    
        std::cout << (i == u) << " vs " << (SignedIntCompare(i) == u) << std::endl;
    
        return 0;
    }
    

    此时,您可以使用EXPECT_TRUE 或类似的布尔检查,如下所示:

    TEST(foo, bar) {
        int id = -99;
        setId(id);
        EXPECT_TRUE(SignedUnsignedIntCompare<decltype(ID)>(ID) == id);
    }
    

    【讨论】:

      最近更新 更多