Dependency injection with unique_ptr to mock

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<memory>
#include<iostream>
#include<utility>

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<IBar> bar) : bar(std::move(bar)) {}

    void DoIt() {
        bar->DoSth();
    }
private:
    std::unique_ptr<IBar> bar;
};

int main() {
    std::unique_ptr<Bar> bar = std::make_unique<Bar>();
    std::shared_ptr<Bar> shared{std::shared_ptr<Bar>{}, 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<BarMock> bar = std::make_unique<BarMock>();
        barMock = std::shared_ptr<BarMock>{std::shared_ptr<BarMock>{}, bar.get()};
        out = std::make_unique<Foo>{std::move(bar)};
    }

    std::shared_ptr<BarMock> barMock;
    std::unique_ptr<Foo> 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<Y>& 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()

Leave a Comment