GoogleTest PrintTo 没有被叫去上课

问题描述 投票:0回答:3

我遇到了一个相当奇怪的问题,告诉 googletest 使用 PrintTo 按我想要的方式打印某个类。
该类是一个非常简单的 2D 点,它位于一个命名空间中,并且 PrintTo 函数位于同一命名空间中。事实上,我有一个可以完美打印的派生类(3D 点)。

这是测试和 PrintTo 函数的一些代码(命名空间名称已编辑,但其他所有内容都是从实际代码复制和粘贴的):

// PrintTo Functions
namespace MyNamespace
{
    void PrintTo(const MyNamespace::CPunto2D& pto, ::std::ostream* os)
    {
        *os << "(";
        *os << pto.X();
        *os << ",";
        *os << pto.Y();
        *os << ")";
    }

    void PrintTo(const MyNamespace::CPunto3D& pto, ::std::ostream* os)
    {
        *os << "(";
        *os << pto.X();
        *os << ",";
        *os << pto.Y();
        *os << ",";
        *os << pto.m_Z;
        *os << ")";
    }
}

// Tests
TEST(TestPrintTo, TestPunto2D)
{
    MyNamespace::CPunto2D p1(1,1);
    MyNamespace::CPunto2D pRef(5,6);

    ASSERT_THAT(p1, Eq(pRef));
}

TEST(TestPrintTo, TestPunto3D)
{
    MyNamespace::CPunto3D pCentro(1,1,1);
    MyNamespace::CPunto3D pRef(5,6,7);

    ASSERT_THAT(pCentro, Eq(pRef));
}

// Output
[ RUN      ] TestPrintTo.TestPunto2D
.\TestPuntoEje.cpp(82): error: Value of: p1
Expected: is equal to 16-byte object <00-00 00-00 00-00 14-40 00-00 00-00 00-00 18-40>
  Actual: 16-byte object <00-00 00-00 00-00 F0-3F 00-00 00-00 00-00 F0-3F> (of type class MyNamespace::CPunto2D)
[  FAILED  ] TestPrintTo.TestPunto2D (1 ms)
[ RUN      ] TestPrintTo.TestPunto3D
.\TestPuntoEje.cpp(90): error: Value of: pCentro
Expected: is equal to (5,6,7)
  Actual: (1,1,1) (of type class MyNamespace::CPunto3D)
[  FAILED  ] TestPrintTo.TestPunto3D (0 ms)

我尝试在一个简单的测试项目中复制该问题,但它打印得很完美。我能想到的测试项目和真实项目之间的唯一区别是,在真实项目中,类 CPunto2D 和 CPunto3D 位于 dll 中,当然还有更多类,并且它们依赖于库。

知道为什么它不选择 PrintTo 功能吗?

我正在使用 Visual Studio 2008 和 googletest 1.7

注意:尽管示例使用了 GMock 的 ASSERT_THAT,但我用 ASSERT_EQ 尝试过,结果是一样的。

更新:

以下是 CPunto2D 和 CPunto3D 的声明。 CLAS_DEC 只是一个用于从 dll 导入/导出的宏。我知道类中有大约一百万个问题,例如公共成员等,所以如果这些问题与当前的问题无关,请不要指出这些问题。

namespace MyNamespace
{
    class CLAS_DEC CPunto2D
    {
    public:
        double m_X;
        double X() const { return m_X; }
        void X(double val) { m_X = val; }
        double m_Y;
        double Y() const { return m_Y; }
        void Y(double val) { m_Y = val; }
        //Constructores/Destructores
        CPunto2D();
        CPunto2D(double X, double Y);
        CPunto2D(const CPunto2D& P);
        ~CPunto2D();

        CPunto2D& Set(double X, double Y);

        //Operadores
        CPunto2D& operator =(const CPunto2D& P);

        //Funciones extra
        double Distancia (const CPunto2D& P) const;  //Distancia a otro punto
    };
    bool CLAS_DEC operator==(const CPunto2D& lhs, const CPunto2D& rhs);
    bool CLAS_DEC operator!=(const CPunto2D& lhs, const CPunto2D& rhs);
}

namespace MyNamespace
{
    class CLAS_DEC CPunto3D : public CPunto2D
    {
    public:
        double m_Z;

        // Constructores/Destructores
        CPunto3D();
        CPunto3D(double X, double Y, double Z);
        CPunto3D(const CPunto3D& P);
        CPunto3D(const CPunto2D& P);
        ~CPunto3D();

        CPunto3D& Set(double X, double Y, double Z);

        // Operadores
        CPunto3D& operator =(const CPunto3D& P);
        bool operator==(const CPunto3D& P) const;
        bool operator!=(const CPunto3D& P) const;

        // Funciones Extra
        double Distancia (const CPunto3D& P) const;  //Distancia a otro punto
        double Distancia2D (const CPunto2D& P) const;  //Distancia en el plano a otro punto
    };
}
c++ googletest one-definition-rule
3个回答
19
投票

问题是您破坏了 gtest 函数之一的 One Definition Rule (ODR) (可能

template ::testing::PrintToString<MyNamespace::CPunto2D>(const MyNamespace::CPunto2D&)
)。

在使用

ASSERT_EQ
的一个 TU 中,未声明
void PrintTo(const MyNamespace::CPunto2D& pto, ::std::ostream* os)
, 所以
::testing::PrintToString<MyNamespace::CPunto2D>
使用默认打印机。

在您使用

ASSERT_EQ
的其他 TU 中,您已声明(并可能定义)
void PrintTo(const MyNamespace::CPunto2D& pto, ::std::ostream* os)
,因此
::testing::PrintToString<MyNamespace::CPunto2D>
使用使用您自定义
PrintTo
的版本。

这是同一函数的第二个不同定义。

您必须确保每个使用

ASSERT_EQ
的 TU 都能看到您的自定义
PrintTo
的声明(如
CPunto2D
的标题中所示)。


1
投票

这让我很困惑,所以我很高兴找到这个解决方案。我的情况是

MyType
有一个
ostream& operator<<()
,但它是在
mytype_io.h
而不是
mytype.h
中定义的。如果任何单元测试 cpp 文件使用
MyType
但不包含
mytype_io.h
那么它将导致
gtest-printers.h
中的默认模板实现被实例化。

所以我的类型没有正确打印。修复方法是确保所有使用

MyType
的单元测试都包含
mytype_io.h


0
投票

可能发生这种情况的另一种情况是,如果您定义一个模拟对象,其中所讨论的类型用作其中一个模拟函数的参数。如果您在定义模拟之后定义打印机,那么 gmock 会以某种方式“锁定”后备打印机而不是您定义的打印机。

© www.soinside.com 2019 - 2024. All rights reserved.