在 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)));

代码编译得很好。根本原因是什么?

您的第一种方法不起作用,因为:

  1. MOCK_[CONST]..._METHOD[0..9]() 在 Mock class 中生成两个函数 - 一个是显而易见的 - 模拟方法的实现,另一个是从名称 gmock_MockedFunction 的 EXPECT_CALL 调用 - 在这种情况下gmock_foo
  2. 这样生成的方法期望作为参数 Matcher<T> 个对象 - 在你的例子中是单个 Matcher<boost::optional<bar>>
  3. Matcher<T> 有两个构造函数 - 一个是显式的 - 所以它不会在你的情况下使用 - 一个是 T 类型的隐式期望值。
  4. 要从 T1 转换为 T2(在您的情况下,从 boost::none_tMatcher<boost::optional<bar>> - 编译器需要使用两个用户定义的转换 - 从 boost::none_tboost::optional<bar> ,然后从 boost::optional<bar>Matcher<boost::optional<bar>> - 两种转换(作为构造函数)都存在 - 但 C++ 只允许在此类转换列表中使用一个用户定义的转换 - 请参阅 this answer
  5. 仅供参考 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)?

  1. Eq(x)(其中 x 的类型为 X)是一个返回 ::testing::internal::EqMatcher<X> 的函数 - 在本例中为 internal::EqMatcher<boost::none_t> - 所以这是您传递给 [=26 的对象类型=]
  2. ::testing::internal::EqMatcher<X> 可(通过用户定义的隐式转换运算符)转换为 Matcher<Y>,其中 Y 是您想要的任何类型 - 例如您可以将 Eq(8) 转换为 Matcher<std::string> - 为了安全起见:一些 std::enable_if(is_comparable) gmock 应该使用...)
  3. 是的 - 满足单个用户定义转换的规则 - 因为此转换运算符是编译器用于从 internal::EqMatcher 转换为 Matcher
  4. 的唯一一次转换

我认为 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...

中提出了这个问题