在 UT 中匹配 boost:none
Matching boost:none in UTs
我有一个public函数:
virtual void foo(boost::optional<bar> p_param) = 0;
和它的模拟:
MOCK_METHOD1(foo, void(boost::optional<bar>));
当我写这样的 expect-call 时:
EXPECT_CALL(aMock, foo(boost::none));
我收到一个错误:
error: no matching function for call to 'testing::StrictMock<AMockClass>::gmock_foo(bar boost::detail::none_helper::* const&)'
有信息:
note: no known conversion for argument 1 from 'const none_t {aka int boost::detail::none_helper::* const}' to 'const testing::Matcher<boost::optional<bar> >&'
然而,当 expect-call 的 arg 被 Eq 匹配器包裹时:
EXPECT_CALL(aMock, foo(Eq(boost::none)));
代码编译得很好。根本原因是什么?
您的第一种方法不起作用,因为:
- 宏
MOCK_[CONST]..._METHOD[0..9]()
在 Mock class 中生成两个函数 - 一个是显而易见的 - 模拟方法的实现,另一个是从名称 gmock_MockedFunction
的 EXPECT_CALL 调用 - 在这种情况下gmock_foo
- 这样生成的方法期望作为参数
Matcher<T>
个对象 - 在你的例子中是单个 Matcher<boost::optional<bar>>
Matcher<T>
有两个构造函数 - 一个是显式的 - 所以它不会在你的情况下使用 - 一个是 T 类型的隐式期望值。
- 要从 T1 转换为 T2(在您的情况下,从
boost::none_t
到 Matcher<boost::optional<bar>>
- 编译器需要使用两个用户定义的转换 - 从 boost::none_t
到 boost::optional<bar>
,然后从 boost::optional<bar>
到 Matcher<boost::optional<bar>>
- 两种转换(作为构造函数)都存在 - 但 C++ 只允许在此类转换列表中使用一个用户定义的转换 - 请参阅 this answer
- 仅供参考 gmock 专门针对字符串类型的 Matcher 以允许从原始字符串进行隐式构造:
看到这个
template <>
class Matcher<internal::string>
: public internal::MatcherBase<internal::string> {
public:
Matcher() {}
explicit Matcher(const MatcherInterface<internal::string>* impl)
: internal::MatcherBase<internal::string>(impl) {}
// Allows the user to write str instead of Eq(str) sometimes, where
// str is a string object.
Matcher(const internal::string& s); // NOLINT
// Allows the user to write "foo" instead of Eq("foo") sometimes.
Matcher(const char* s); // NOLINT
};
那么 - 为什么它适用于 Eq(boost::none)?
Eq(x)
(其中 x 的类型为 X)是一个返回 ::testing::internal::EqMatcher<X>
的函数 - 在本例中为 internal::EqMatcher<boost::none_t>
- 所以这是您传递给 [=26 的对象类型=]
::testing::internal::EqMatcher<X>
可(通过用户定义的隐式转换运算符)转换为 Matcher<Y>
,其中 Y
是您想要的任何类型 - 例如您可以将 Eq(8)
转换为 Matcher<std::string>
- 为了安全起见:一些 std::enable_if(is_comparable) gmock 应该使用...)
- 是的 - 满足单个用户定义转换的规则 - 因为此转换运算符是编译器用于从 internal::EqMatcher 转换为 Matcher
的唯一一次转换
我认为 gmock 知道 boost 库并对其进行一些专门化会很好 - 正如它对 std::string - 所以你可以写 EXPECT_CALL(mock, foo("Hello")) 对于需要 std::string 的函数。以同样的方式,它可以是 Matcher> 的专业化,以允许按照您在问题中的预期进行写作。让我们问问 gmock 的人吧...
[更新]
我在 gmock forum - no enthusiasm so far... It could be expected that they do not want to have such strong relationship to non-standard library like boost. I will return to the subject when optional will be standard - now I see it is experimental...
中提出了这个问题
我有一个public函数:
virtual void foo(boost::optional<bar> p_param) = 0;
和它的模拟:
MOCK_METHOD1(foo, void(boost::optional<bar>));
当我写这样的 expect-call 时:
EXPECT_CALL(aMock, foo(boost::none));
我收到一个错误:
error: no matching function for call to 'testing::StrictMock<AMockClass>::gmock_foo(bar boost::detail::none_helper::* const&)'
有信息:
note: no known conversion for argument 1 from 'const none_t {aka int boost::detail::none_helper::* const}' to 'const testing::Matcher<boost::optional<bar> >&'
然而,当 expect-call 的 arg 被 Eq 匹配器包裹时:
EXPECT_CALL(aMock, foo(Eq(boost::none)));
代码编译得很好。根本原因是什么?
您的第一种方法不起作用,因为:
- 宏
MOCK_[CONST]..._METHOD[0..9]()
在 Mock class 中生成两个函数 - 一个是显而易见的 - 模拟方法的实现,另一个是从名称gmock_MockedFunction
的 EXPECT_CALL 调用 - 在这种情况下gmock_foo
- 这样生成的方法期望作为参数
Matcher<T>
个对象 - 在你的例子中是单个Matcher<boost::optional<bar>>
Matcher<T>
有两个构造函数 - 一个是显式的 - 所以它不会在你的情况下使用 - 一个是 T 类型的隐式期望值。- 要从 T1 转换为 T2(在您的情况下,从
boost::none_t
到Matcher<boost::optional<bar>>
- 编译器需要使用两个用户定义的转换 - 从boost::none_t
到boost::optional<bar>
,然后从boost::optional<bar>
到Matcher<boost::optional<bar>>
- 两种转换(作为构造函数)都存在 - 但 C++ 只允许在此类转换列表中使用一个用户定义的转换 - 请参阅 this answer - 仅供参考 gmock 专门针对字符串类型的 Matcher 以允许从原始字符串进行隐式构造:
看到这个
template <>
class Matcher<internal::string>
: public internal::MatcherBase<internal::string> {
public:
Matcher() {}
explicit Matcher(const MatcherInterface<internal::string>* impl)
: internal::MatcherBase<internal::string>(impl) {}
// Allows the user to write str instead of Eq(str) sometimes, where
// str is a string object.
Matcher(const internal::string& s); // NOLINT
// Allows the user to write "foo" instead of Eq("foo") sometimes.
Matcher(const char* s); // NOLINT
};
那么 - 为什么它适用于 Eq(boost::none)?
Eq(x)
(其中 x 的类型为 X)是一个返回::testing::internal::EqMatcher<X>
的函数 - 在本例中为internal::EqMatcher<boost::none_t>
- 所以这是您传递给 [=26 的对象类型=]::testing::internal::EqMatcher<X>
可(通过用户定义的隐式转换运算符)转换为Matcher<Y>
,其中Y
是您想要的任何类型 - 例如您可以将Eq(8)
转换为Matcher<std::string>
- 为了安全起见:一些 std::enable_if(is_comparable) gmock 应该使用...)- 是的 - 满足单个用户定义转换的规则 - 因为此转换运算符是编译器用于从 internal::EqMatcher 转换为 Matcher 的唯一一次转换
我认为 gmock 知道 boost 库并对其进行一些专门化会很好 - 正如它对 std::string - 所以你可以写 EXPECT_CALL(mock, foo("Hello")) 对于需要 std::string 的函数。以同样的方式,它可以是 Matcher> 的专业化,以允许按照您在问题中的预期进行写作。让我们问问 gmock 的人吧...
[更新]
我在 gmock forum - no enthusiasm so far... It could be expected that they do not want to have such strong relationship to non-standard library like boost. I will return to the subject when optional will be standard - now I see it is experimental...
中提出了这个问题