Search code examples
c++unit-testinggooglemock

Mock in the Middle with C++/Gmock


I have a class A that instantiates an object of class B in its constructor. I want to test A with a mock object of B.

And no, I can not pass object of B as a parameter. Is there any other way?

I saw an article http://www.ibm.com/developerworks/library/j-mocktest/index.html, with "Mock in the Middle" as the interesting topic, but that is in Java. Is it possible in C++?

class B {...};

class A {
  private:
    B* b;

  public:
    A() {
        b = new B();
    }
    ~A() {..}
};

EDIT:

In general, the object may be created in some other method, on demand. For example,

class A {
    ...
    int doSomething() {
        // Create an object of class B
        b = new B();
    }
}; 

Solution

  • You can use factory pattern


    given this code

    class B {
      public:
        virtual std::string name() { return "B::name"; }
        virtual ~B() {}
    };
    
    class A {
      private:
        std::unique_ptr<B> b;
    
      public:
        A() {}
        void createB() {
            b.reset(new B); // you want to replace `new B` with something else right?
        }
        void print() {
            std::cout << (b ? b->name() : std::string()) << std::endl;
        }
        ~A() {}
    };
    

    with factory function

    class A {
      private:
        std::unique_ptr<B> b;
    
      public:
        std::function<std::unique_ptr<B>()> b_maker;
    
        A() {
            // default maker
            b_maker = []{ return std::unique_ptr<B>(new B); };
        }
    
        A(std::function<std::unique_ptr<B>()> func) {
            b_maker = func;
        }
    
        void createB() {
            b = b_maker();
        }
    
        void print() {
            std::cout << (b ? b->name() : std::string()) << std::endl;
        }
        ~A() {}
    };
    

    create A with default B is same

    A();
    

    and now you can supply mocked B with

    A([]{return std::unique_ptr<B>{new MockedB};});
    

    live demo


    you can also make b_maker to be a global variable so you don't need to pass it around (but I don't recommended to to it)


    you can do it with the complicated way with AbstractBFactory, BFactory, MockBFactory, but it is too much overhead and looks like Java...