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 Foo):
using namespace std;
struct IBar {
    virtual ~IBar() = default;  
    virtual void DoSth() = 0;
};
struct Bar : public IBar {
    void DoSth() override { cout <<"Bar is doing sth" << endl;};    
};
struct Foo {
  Foo(unique_ptr<IBar> bar) : bar_(std::move(bar)) {}
  void DoIt() {
    bar_->DoSth();
  }
private:
  unique_ptr<IBar> bar_;
};
So far so good, this works fine. However, I have a problem when I want to unit test the code:
namespace {
struct BarMock : public IBar {
  MOCK_METHOD0(DoSth, void());
};
}
struct FooTest : public Test {
  FooTest() : barMock{ make_unique<BarMock>() }, out(std::move(barMock)) {}
  unique_ptr<BarMock> barMock;
  Foo out;
};
TEST_F(FooTest, shouldDoItWhenDoSth) {
  EXPECT_CALL(*barMock, DoSth());
  out.DoIt();
}
The test fails because the mock object was transfered fo Foo, and setting an expectation on such mock fails.
Possible options of DI:
The only solution I got is to store raw pointer to BarMock before Foo become solely owner of BarMock, i.e.:
struct FooTest : public Test {
  FooTest() : barMock{new BarMock} {
    auto ptr = unique_ptr<BarMock>(barMock);
    out.reset(new Foo(std::move(ptr)));
  }
  BarMock* barMock;
  unique_ptr<Foo> out;
};
Isn't there a cleaner solution? Do I have to use static dependency injection (templates)?
Use unique_ptr when you want a single pointer to an object that will be reclaimed when that single pointer is destroyed. Use shared_ptr when you want multiple pointers to the same resource.
Use unique_ptr when you want to have single ownership(Exclusive) of the resource. Only one unique_ptr can point to one resource. Since there can be one unique_ptr for single resource its not possible to copy one unique_ptr to another. A shared_ptr is a container for raw pointers.
A unique_ptr does not share its pointer. It cannot be copied to another unique_ptr , passed by value to a function, or used in any C++ Standard Library algorithm that requires copies to be made. A unique_ptr can only be moved.
std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.
You can keep a reference to the mocked object before passing it to the constructor.  I think it makes the code a tad bit brittle, due to member initialization ordering, but it is clearer semantically what it means.  Ownership of BarMock still belongs solely to Foo, with a reference handle kept by FooTest (similar to this answer).
Basically the same as your answer, but using reference instead of a raw pointer
class FooTest : public ::testing::Test
{
    protected:
        FooTest() :
            bar_mock_ptr(std::make_unique<BarMock>()),
            bar_mock(*bar_mock_ptr),
            foo(std::move(bar_mock_ptr))
        {}
    private:
        // This must be declared before bar_mock due to how member initialization is ordered
        std::unique_ptr<BarMock> bar_mock_ptr; // moved and should not be used anymore
    protected:
        BarMock& bar_mock;
        Foo foo; //ensure foo has the same lifetime as bar_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_ptrwhich shares ownership information withr, but holds an unrelated and unmanaged pointerptr. Even if thisshared_ptris the last of the group to go out of scope, it will call the destructor for the object originally managed byr. However, callingget()on this will always return a copy ofptr. It is the responsibility of the programmer to make sure that thisptrremains valid as long as thisshared_ptrexists, such as in the typical use cases whereptris a member of the object managed byror is an alias (e.g., downcast) ofr.get()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With