【问题标题】:How to use shared_ptr to supply mock object from outside?如何使用 shared_ptr 从外部提供模拟对象?
【发布时间】:2017-11-09 10:58:45
【问题描述】:

我想测试一个应用程序Thud,它将使用资源Foo。它不会拥有一个具体的对象,但会有一个指向抽象资源接口的指针(此处为IFoo)。在生产中,我将为它提供实际的资源实现 (FooImpl),而对于单元测试,我想发送一个指向模拟资源的指针。我该怎么做?我试图写最少的代码只是为了指出,

class IFoo
{
public:
    virtual bool Foo(bool) = 0;
};

class FooImpl : public IFoo
{
public:
    bool Foo(bool b) override
    {
        return b;
    }
};

class FooMock : public IFoo
{
public:
    MOCK_METHOD1(Foo, bool(bool));
};

class ThudTest : public ::testing::Test
{
protected:
    virtual void SetUp() {
        //foo.reset(&mock); //line#1
        foo = &mock; //line#2
    }

    FooMock mock;
    //std::shared_ptr<IFoo> foo; //line#3
    IFoo* foo; //line#4
};

class Thud
{
    //std::shared_ptr<IFoo> fooPtr; //line#5
    IFoo* fooPtr; //line#6
public:
    /*Thud(std::shared_ptr<IFoo> fooPtr_) : fooPtr{ fooPtr_ }
    {}*/ //line#7
    Thud(IFoo* fooPtr_) : fooPtr{ fooPtr_ }
    {} //line#8
    bool thud1(bool b)
    {
        return fooPtr->Foo(b);
    }
};

TEST_F(ThudTest, fooFalse)
{
    bool b = false;
    EXPECT_CALL(mock, Foo(b)).Times(1).WillOnce(Return(false));;

    Thud thud(foo);
    EXPECT_FALSE(thud.thud1(b));
}

TEST_F(ThudTest, fooTrue)
{
    bool b = true;
    EXPECT_CALL(mock, Foo(b)).Times(1).WillOnce(Return(true));;

    Thud thud(foo);
    EXPECT_TRUE(thud.thud1(b));
}

int main(int argc, char** argv) {
    // The following line must be executed to initialize Google Mock
    // (and Google Test) before running the tests.
    ::testing::InitGoogleMock(&argc, argv);
    return RUN_ALL_TESTS();
}

所以为了完成,我有一个重载的构造函数,它不需要争论,但会做以下事情,

Thud():fooPtr {std::make_shared<FooImpl>()}
{}

在生产中得到真正的实现。 但是现在我如何使指针指向模拟对象。如您所见,我在这里使用 GMock 框架。如何做到这一点?

如果我注释掉使用普通旧原始指针的第 #2、4、6 和 8 行并取消注释并使用第 1、3、5 和 7 行(在此处使用有问题的 shared_ptr),它会崩溃在第一个测试用例之后出现堆损坏。

它与这个原始指针完美配合。

【问题讨论】:

    标签: c++ unit-testing mocking shared-ptr


    【解决方案1】:

    你不能做foo.reset(&amp;mock),从那时起mock有两个所有者:它的自动存储持续时间,加上共享指针foo。内存损坏 FTW。

    您应该简单地动态分配FooMock 并在创建正在测试的Thud 实例时将其传入:

    class ThudTest : public ::testing::Test
    {
    protected:
        virtual void SetUp() {
            foo = std::make_shared<FooMock>();
        }
    
        std::shared_ptr<FooMock> foo;
    };
    

    您甚至不再需要mock 成员。请注意,我已更改 foo 的类型以了解 FooMock,以便您可以访问该类型。如果您真的希望 foo 保持模拟不感知,请这样做:

    class ThudTest : public ::testing::Test
    {
    protected:
        virtual void SetUp() {
            mock = std::make_shared<FooMock>();
            foo = mock;
        }
    
        std::shared_ptr<FooMock> mock;
        std::shared_ptr<IFoo> foo;
    };
    

    但是,这不是必需的,因为 std::shared_ptr&lt;FooMock&gt; 可以隐式转换为 std::shared_ptr&lt;IFoo&gt;

    【讨论】:

    • 谢谢安吉。是的,我认为这就是我需要的。但是,我应该怎么做呢?我是这些智能指针的新手。
    • 但是,如果不是 mock 对象,我应该将什么对象传递给我的期望子句 EXPECT_CALL(mock, Foo(b)).Times(1).WillOnce(Return(false)); ?我应该对哪个对象设定期望?
    • 你在模拟中设定了你的期望。
    • @user3222 mock 对象归ThudTest::foo 所有,所以你可以用它来引用它。
    • @robert:这就是重点,OP 没有模拟对象,(或者他必须投射它:/)
    【解决方案2】:

    与:

    class Thud
    {
        std::shared_ptr<IFoo> fooPtr;
    public:
        Thud(std::shared_ptr<IFoo> fooPtr_) : fooPtr{ fooPtr_ }
        {}
        bool thud1(bool b)
        {
            return fooPtr->Foo(b);
        }
    };
    

    您的测试可以变成(我删除了该功能):

    TEST(ThudTest, fooFalse)
    {
        auto mock = std::make_shared<FooMock>()
        bool b = false;
        EXPECT_CALL(*mock, Foo(b)).Times(1).WillOnce(Return(false));;
    
        Thud thud(mock);
        EXPECT_FALSE(thud.thud1(b));
    }
    
    TEST(ThudTest, fooTrue)
    {
        auto mock = std::make_shared<FooMock>()
        bool b = true;
        EXPECT_CALL(*mock, Foo(b)).Times(1).WillOnce(Return(true));;
    
        Thud thud(mock);
        EXPECT_TRUE(thud.thud1(b));
    }
    

    【讨论】:

      【解决方案3】:

      在我的解决方案中,需要使用shared_ptr&lt;IFoo&gt; 将其添加到其他测试类的集合中,我想出使用referecne ;)。然后我也尝试了NiceMock&lt;IFoo&gt;StrictMock&lt;IFoo&gt; 并且成功了。

      using namespace testing;
      using namespace std;
      
      class ThudTest : public Test {
        public:
          shared_ptr<FooMock> fooPtr_ = make_shared<FooMock>();
          // shared_ptr<StrictMock<FooMock>> fooPtr_ = make_shared<StrictMock<FooMock>>();
          FooMock& mock = *fooPtr_;
          // StrictMock<FooMock>& mock= *fooPtr_;
      
          bool thud1(bool b) {
              return fooPtr_->Foo(b);
          }
      };
      

      没有*也可以编写测试:

      TEST_F(ThudTest, fooFalse) {
          bool b = false;
          EXPECT_CALL(mock, Foo(b)).Times(1).WillOnce(Return(false));
      
          EXPECT_FALSE(thud1(b));
      }
      
      TEST_F(ThudTest, fooTrue) {
          bool b = true;
          EXPECT_CALL(mock, Foo(b)).Times(1).WillOnce(Return(true));
      
          EXPECT_TRUE(thud1(b));
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-04
        • 1970-01-01
        • 1970-01-01
        • 2018-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多