如何使用 gmock 匹配 C++ 元组中的一个元素?

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

如何使用 gmock 匹配 C++ 元组中的一个元素?

例如,让我们尝试从

std::string
中提取
std::tuple<std::string, int>

我知道我可以编写这样的自定义匹配器:

MATCHER_P(match0thOfTuple, expected, "") { return (std::get<0>(arg) == expected); }

但是自从我找到了

Pair(m1, m2)
std::pair
匹配器后,我希望也能为
std::tuple
找到类似的东西。

Gmock 有

Args<N1, N2, ..., Nk>(m)
用于选择元组参数的子集。当仅使用 1 个参数时,它仍然需要一个元组匹配器。以下尝试似乎无法编译:

struct {
  MOCK_METHOD1(mockedFunction, void(std::tuple<std::string, int>&));
} mock;
EXPECT_CALL(mock, mockedFunction(testing::Args<0>(testing::Eq(expectedStringValue))));

并使我的 clang 给出这样的编译错误:

.../gtest/googlemock/include/gmock/gmock-matchers.h:204:60: error: invalid operands to binary expression ('const std::__1::tuple<std::__1::basic_string<char> >' and 'const std::__1::basic_string<char>')
  bool operator()(const A& a, const B& b) const { return a == b; }
...

是否有针对

std::tuple
的 gmock 解决方案类似于
std::pair
的解决方案,它使用 gmock
Pair
匹配器?

c++ googletest googlemock
2个回答
2
投票

testing::Args
用于将函数参数打包到元组中 - 与您想要实现的目标完全相反。

我的建议 - 对于你的情况 - 在模拟类中解压,请参阅:

struct mock 
{
  void mockedFunction(std::tuple<std::string, int>& tt)
  {
      mockedFunctionUnpacked(std::get<0>(tt), std::get<1>(tt));
  }
  MOCK_METHOD2(mockedFunctionUnpacked, void(std::string&, int&));
};

然后:

EXPECT_CALL(mock, mockedFunctionUnpacked(expectedStringValue, ::testing::_));

不幸的是,当前的 gmock 匹配器都不适用于 std::tuple 参数。



如果您想了解 C++ 模板 - 您可以尝试这个(不完整 - 只是一个想法如何实现元组匹配的通用函数):

// Needed to use ::testing::Property - no other way to access one 
// tuple element as "member function"
template <typename Tuple>
struct TupleView
{
public:
    TupleView(Tuple const& tuple) : tuple(tuple) {}
    template <std::size_t I>
    const typename std::tuple_element<I, Tuple>::type& get() const
    {
        return std::get<I>(tuple);
    }
private:
    Tuple const& tuple;
};

// matcher for TupleView as defined above
template <typename Tuple, typename ...M, std::size_t ...I>
auto matchTupleView(M ...m, std::index_sequence<I...>)
{
    namespace tst = ::testing;
    using TV = TupleView<Tuple>;
    return tst::AllOf(tst::Property(&TV::template get<I>, m)...);
}

// Matcher to Tuple - big disadvantage - requires to provide tuple type:
template <typename Tuple, typename ...M>
auto matchTupleElements(M ...m)
{
    auto mtv = matchTupleView<Tuple, M...>(m..., std::make_index_sequence<sizeof...(M)>{});
    return ::testing::MatcherCast<TupleView<Tuple>>(mtv);
}

然后像这样使用:

EXPECT_CALL(mock, mockedFunction(matchTupleElements<std::tuple<std::string, int>>(expectedStringValue, ::testing::_)));

0
投票

2020 年 10 月 15 日,元组匹配器已添加到 googletest。这个新的匹配器称为

FieldsAre
,现在在匹配器参考中也提到了

它的用法与

Pair
相同,这里需要注意的是,两者都不能按照您的要求提取特定元素。

auto const value = std::tuple{ std::string{ "foo" }, 42, 3.14 };
EXPECT_THAT(value, FieldsAre("foo", 42, 3.14));

// You can use any matcher as usual
EXPECT_THAT(value, FieldsAre(SizeIs(3), Ge(41), Ne(2.71)));

// To "extract" a field you could ignore the others with _
EXPECT_THAT(value, FieldsAre("foo", _, _));
© www.soinside.com 2019 - 2024. All rights reserved.