我有一个相当奇怪的问题,告诉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
};
}
答案 0 :(得分:9)
问题是你打破了其中一个gtest函数的 O ne D 定义 R ule(ODR)
(可能是artifactId
)。
在您使用template ::testing::PrintToString<MyNamespace::CPunto2D>(const MyNamespace::CPunto2D&)
的一个TU中,未声明ASSERT_EQ
,
所以void PrintTo(const MyNamespace::CPunto2D& pto, ::std::ostream* os)
使用默认打印机。
在您使用::testing::PrintToString<MyNamespace::CPunto2D>
的其他TU中,您已声明(并可能已定义)ASSERT_EQ
,因此void PrintTo(const MyNamespace::CPunto2D& pto, ::std::ostream* os)
会使用您的自定义::testing::PrintToString<MyNamespace::CPunto2D>
版本。
这是同一功能的第二个不同的定义。
您必须确保使用PrintTo
的每个TU都能看到自定义ASSERT_EQ
的声明(如PrintTo
标题中所示)。
答案 1 :(得分:0)
这让我很困惑,所以我很高兴找到这个解决方案。我的情况是 MyType
有一个 ostream& operator<<()
,但它是在 mytype_io.h
而不是 mytype.h
中定义的。如果任何单元测试 cpp 文件使用 MyType
但不包含 mytype_io.h
,那么它将导致 gtest-printers.h
中的默认模板实现被实例化。
所以我的类型没有被正确打印。修复是为了确保所有使用 MyType
的单元测试都包含 mytype_io.h
。