模板类内嵌结构体成员GTest验证函数封装编译报错排查
问题
我有一个单元测试,用于验证模板类Object的内嵌结构体Values的成员valueA、valueB是否等于0。希望将验证逻辑封装到一个函数中,替代重复调用EXPECT_NE/EXPECT_EQ的操作。
原测试代码如下:
template<typename T> struct Object { struct Values { int valueA; int valueB; }; Values values = {}; T otherStuff; void setValues(int valueA, int valueB) { values.valueA = valueA; values.valueB = valueB; } }; TEST(UnitTest, testA) { Object<int> object; // do stuff that modified object's values via setValues() EXPECT_NE(object.values.valueA, 0); EXPECT_EQ(object.values.valueB, 0); }
尝试封装后出现编译错误:
gmock-matchers.h:2074:31: error: no matching function for call to 'testing::internal::FieldMatcher<Object<int>::Values, int>::MatchAndExplainImpl(std::integral_constant<bool, false>::type, const Object<int>&, testing::MatchResultListener*&) const' 2074 | return MatchAndExplainImpl( | ~~~~~~~~~~~~~~~~~~~^ 2075 | typename std::is_pointer<typename std::remove_const<T>::type>::type(), | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2076 | value, listener);
若使用Object的外层成员变量testVar进行封装则编译正常,请问为何内嵌结构体成员会出现报错?
封装后的完整代码:
using ::testing::Eq; using ::testing::Ne; using ::testing::Field; using ::testing::AllOf; template<typename T> struct Object { int testVar; struct Values { int valueA; int valueB; }; Values values = {}; T otherStuff; void setValues(int valueA, int valueB) { values.valueA = valueA; values.valueB = valueB; } }; template <typename T, class M1, class M2> auto MatchesStruct(M1 m1, M2 m2) { return AllOf(Field(&Object<T>::Values::valueA, m1), Field(&Object<T>::Values::valueB, m2)); } TEST(UnitTest, testA) { Object<int> object; // do stuff that modified object's values via setValues() EXPECT_THAT(object, MatchesStruct<int>(Ne(0), Eq(0))); }
原因分析与解决方案
报错原因
当前写法中,Field(&Object<T>::Values::valueA, m1)直接传入了内嵌结构体Values的成员指针,但EXPECT_THAT的目标对象是Object<T>类型——GMock的Field匹配器要求第一个参数必须是目标对象类型的成员指针,两者类型不匹配,因此触发编译错误。
而外层成员testVar能正常编译,是因为&Object<T>::testVar是Object<T>类型的成员指针,与EXPECT_THAT的目标对象类型完全一致,匹配器可以正确解析。
修复方案
需要先通过Field匹配器从Object<T>对象中取出values成员,再嵌套使用Field匹配其内部的valueA和valueB。调整后的封装函数如下:
template <typename T, class M1, class M2> auto MatchesStruct(M1 m1, M2 m2) { return Field(&Object<T>::values, AllOf(Field(&Object<T>::Values::valueA, m1), Field(&Object<T>::Values::valueB, m2))); }
第一层Field负责从Object<T>中提取values成员,第二层通过AllOf组合两个Field匹配器,分别验证values内部的valueA和valueB,类型完全匹配后即可正常编译并执行验证逻辑。
内容的提问来源于stack exchange,提问作者xyf
相关产品推荐
相关产品推荐

