假冒的Google模拟委托必须是可复制构造的

问题描述 投票:1回答:1

使用Google测试和模拟,如果函数返回对数据对象的引用,则似乎无法将模拟的调用委派给虚假对象。我使用的Google测试版本是发布的zip中的1.10.0。

在下面的代码中,当我从模拟委托给伪造品时,出现错误,指示复制ctor被删除。是的,必须删除它才能使此代码正常工作。

对于将返回对类的引用的函数,有没有办法使用gmock将模拟委派给伪造品?

请注意,在下面的代码中,有一个宏:#define USE_MOCK_ACCESSOR 1这用于测试所需的测试代码执行路径。将此值定义为零仅测试AccessorImpl类的正确行为。我这样做是为了检查我是否在某种程度上不会畸形该类中的类和实例。感谢您的输入。

#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include <cstdint>

using ::testing::Invoke;
using ::testing::Mock;
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::_;

class Accessor
{
public:
    virtual ~Accessor()                  = default;
    Accessor()                           = default;
    Accessor(Accessor const&)            = delete;
    Accessor(Accessor&&)                 = delete;
    Accessor& operator=(Accessor const&) = delete;
    Accessor& operator=(Accessor&&)      = delete;

    struct Foo
    {
        ~Foo()                     = default;
        Foo()                      = default;
        Foo(Foo const&)            = delete;
        Foo(Foo&&)                 = delete;
        Foo& operator=(Foo const&) = delete;
        Foo& operator=(Foo&&)      = delete;

        uint32_t thing_1 = 13u;
    };

    struct Bar
    {
        ~Bar()                     = default;
        Bar()                      = default;
        Bar(Bar const&)            = delete;
        Bar(Bar&&)                 = delete;
        Bar& operator=(Bar const&) = delete;
        Bar& operator=(Bar&&)      = delete;

        uint32_t thing_2 = 79u;
    };

    virtual Foo&       GetFoo()       = 0;
    virtual Bar const& GetBar() const = 0;
};

class AccessorImpl: public Accessor
{
public:
    ~AccessorImpl() override                       = default;
    AccessorImpl()                                 = default;
    AccessorImpl(AccessorImpl const& ) = delete;
    AccessorImpl(AccessorImpl&&)                   = delete;
    AccessorImpl& operator=(AccessorImpl const&)   = delete;
    AccessorImpl& operator=(AccessorImpl&&)        = delete;

    Foo&       GetFoo()       override { return this->foo_; };
    Bar const& GetBar() const override { return this->bar_; };

private:
    Foo foo_;
    Bar bar_;
};

#define USE_MOCK_ACCESSOR 1
#if USE_MOCK_ACCESSOR
class MockAccessor : public Accessor
{
public:
    MOCK_METHOD0(GetFoo, Foo&());
    MOCK_CONST_METHOD0(GetBar, Bar&());
};

class MockAccessorWithFake : public MockAccessor
{
public:
    MockAccessorWithFake() : MockAccessor(), fake_accessor_()
    {
        ON_CALL(*this, GetFoo).WillByDefault([this]() {
            return this->fake_accessor_.GetFoo();
        });

        ON_CALL(*this, GetBar).WillByDefault([this]() {
            return this->fake_accessor_.GetBar();
        });
    }

private:
    AccessorImpl fake_accessor_;
};
#endif

TEST(AccessorTest, test)
{
#if USE_MOCK_ACCESSOR
    MockAccessorWithFake accessor;
#else
    AccessorImpl accessor;
#endif
    EXPECT_EQ(accessor.GetFoo().thing_1, 13u);
    EXPECT_EQ(accessor.GetBar().thing_2, 79u);
}

来自clang编译器的错误:

test_accessor.cc:83:20: error: call to deleted constructor of 'Accessor::Foo'
            return this->fake_accessor_.GetFoo();
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

test_accessor.cc:26:9: note: 'Foo' has been explicitly marked deleted here
        Foo(Foo const&)            = delete;
        ^

test_accessor.cc:82:46: error: no viable conversion from '(lambda at
      test_accessor.cc:82:46)' to 'const Action<Accessor::Foo &()>'
        ON_CALL(*this, GetFoo).WillByDefault([this]() {
                                             ^~~~~~~~~~

googletest-src/googlemock/include/gmock/gmock-actions.h:339:7: note: candidate constructor (the implicit copy constructor) not viable:
      no known conversion from '(lambda at test_accessor.cc:82:46)' to 'const testing::Action<Accessor::Foo &()> &' for 1st argument
class Action {
      ^

googletest-src/googlemock/include/gmock/gmock-actions.h:339:7: note: candidate constructor (the implicit move constructor) not viable:
      no known conversion from '(lambda at test_accessor.cc:82:46)' to 'testing::Action<Accessor::Foo &()> &&' for 1st argument

googletest-src/googlemock/include/gmock/gmock-actions.h:367:3: note: candidate template ignored: requirement
      '::std::is_constructible<std::__1::function<Accessor::Foo &()>, (lambda at test_accessor.cc:82:46)>::value' was not satisfied
      [with G = (lambda at test_accessor.cc:82:46)]
  Action(G&& fun) : fun_(::std::forward<G>(fun)) {}  // NOLINT
  ^

googletest-src/googlemock/include/gmock/gmock-spec-builders.h:323:46: note: passing argument to parameter 'action' here
  OnCallSpec& WillByDefault(const Action<F>& action) {
c++ googletest gmock
1个回答
0
投票

问题1

auto类型推导条引用的规则。因此,您的lambda的返回类型推导为Foo,而不是Foo&,后者随后需要复制。如果要从lambda返回引用,则必须使用尾随的返回类型语法来显式指定该引用,方法是将返回类型显式设置为Foo&,或者使用auto&强制引用类型推导,或者通过使用decltype(auto)保留引用。参见linklinklink,在最后一个链接中,相关部分是:“如果P是引用类型,则使用P引用的类型进行推导。”

[this]() {return this->fake_accessor_.GetFoo();}          // Returns Foo
[this]() -> Foo& {return this->fake_accessor_.GetFoo();}  // Returns Foo&

[this]() -> auto {return this->fake_accessor_.GetFoo();}  // Returns Foo
[this]() -> auto& {return this->fake_accessor_.GetFoo();} // Returns Foo&

[this]() -> decltype(auto) {return this->fake_accessor_.GetFoo();} // Returns Foo&

因此,您应该更改传递给ON_CALL的lambda以返回引用类型,例如:

        ON_CALL(*this, GetFoo).WillByDefault([this]() -> Foo& {
            return this->fake_accessor_.GetFoo();
        });

        ON_CALL(*this, GetBar).WillByDefault([this]() -> Bar const& {
            return this->fake_accessor_.GetBar();
        });

没有这个,您会得到错误:

test.cpp:83:20: error: call to deleted constructor of 'Accessor::Foo'
            return this->fake_accessor_.GetFoo();
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:26:9: note: 'Foo' has been explicitly marked deleted here
        Foo(Foo const&)            = delete;
        ^
test.cpp:82:46: error: no viable conversion from '(lambda at test.cpp:82:46)' to 'const Action<Accessor::Foo &()>'
        ON_CALL(*this, GetFoo).WillByDefault([this]() {
                                             ^~~~~~~~~~

问题2

GetBar的声明中,const有两种用法:

  1. 该函数是const成员函数(表示它无法修改this的状态)。
  2. 返回值是对const Bar的引用。

MOCK_CONST_METHOD0宏仅声明const成员函数。要覆盖返回值中的const,您的模拟应为:

  MOCK_CONST_METHOD0(GetBar, Bar const&());

如果不进行此更改,将产生以下错误:

test.cpp:86:46: error: no viable conversion from '(lambda at test.cpp:86:46)' to 'const Action<Accessor::Bar &()>'
        ON_CALL(*this, GetBar).WillByDefault([this]() -> Bar const& {
                                             ^~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/gmock/gmock-actions.h:357:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from '(lambda at test.cpp:86:46)' to 'const testing::Action<Accessor::Bar &()> &' for 1st argument
class Action {
© www.soinside.com 2019 - 2024. All rights reserved.