Dependency injection with unique_ptr to mock

前端 未结 3 1075
终归单人心
终归单人心 2020-11-30 12:57

I have a class Foo that uses class Bar. Bar is used only in Foo and Foo is managing Bar, therefore I use unique_ptr (not a reference, because I don\'t need Bar outside of Fo

3条回答
  •  南方客
    南方客 (楼主)
    2020-11-30 13:19

    Not something I would recommend in production environment actually, but aliasing constructor of shared_ptr represents maybe a dirty and working solution for your case.
    A minimal, working example (that doesn't use gtest, sorry, I'm from mobile app and can't test it directly):

    #include
    #include
    #include
    
    struct IBar {
        virtual ~IBar() = default;  
        virtual void DoSth() = 0;
    };
    
    struct Bar : public IBar {
        void DoSth() override { std::cout <<"Bar is doing sth" << std::endl;};    
    };
    
    struct Foo {
        Foo(std::unique_ptr bar) : bar(std::move(bar)) {}
    
        void DoIt() {
            bar->DoSth();
        }
    private:
        std::unique_ptr bar;
    };
    
    int main() {
        std::unique_ptr bar = std::make_unique();
        std::shared_ptr shared{std::shared_ptr{}, bar.get()};
        Foo foo{std::move(bar)};
        shared->DoSth();
        foo.DoIt();
    }
    

    I guess your test would become something like this:

    struct BarMock: public IBar {
        MOCK_METHOD0(DoSth, void());
    };
    
    struct FooTest : public testing::Test {
        FooTest() {
            std::unique_ptr bar = std::make_unique();
            barMock = std::shared_ptr{std::shared_ptr{}, bar.get()};
            out = std::make_unique{std::move(bar)};
        }
    
        std::shared_ptr barMock;
        std::unique_ptr out;
    };
    
    TEST_F(FooTest, shouldDoItWhenDoSth) {
        EXPECT_CALL(*barMock, DoSth());
        out->DoIt();
    }
    

    What does the aliasing constructor do?

    template< class Y > 
    shared_ptr( const shared_ptr& r, element_type *ptr );
    

    The aliasing constructor: constructs a shared_ptr which shares ownership information with r, but holds an unrelated and unmanaged pointer ptr. Even if this shared_ptr is the last of the group to go out of scope, it will call the destructor for the object originally managed by r. However, calling get() on this will always return a copy of ptr. It is the responsibility of the programmer to make sure that this ptr remains valid as long as this shared_ptr exists, such as in the typical use cases where ptr is a member of the object managed by r or is an alias (e.g., downcast) of r.get()

提交回复
热议问题