Mocking C++ classes with dependency injection

2020-03-29 02:45发布

Say you're testing class A and it has a dependency injection of B which has a dependency injection of C.
So you mock B but the only constructor it has requires an injection of C, so do you have to mock C as well and inject the mocked C into the mocked B and only then inject it to A?
What if you have 5 consecutive dependancies?

What are the alternatives?

I use Google Mock, so a specific answer would help as well.

3条回答
时光不老,我们不散
2楼-- · 2020-03-29 03:18

If you change the design so that the classes depend on interfaces instead of concrete classes, you get rid of the constructor problems. Besides improving testability, it may also improve reusability and maintainability, at the cost of more code (interfaces).

查看更多
贪生不怕死
3楼-- · 2020-03-29 03:21

In this case you should inject by pointer and not by reference, then you could pass a NULL pointer. This would work assuming you're object is indeed a mock and not a fake object, therefore it has no real dependency on the injected object.

For boost::shared_ptr you could do the following:

boost::shared_ptr<C> null_c_ptr;
MockB mock_b(null_c_ptr);
查看更多
放荡不羁爱自由
4楼-- · 2020-03-29 03:22

Emile has the right idea, you should depend on interfaces not concrete classes. So in your example it would be something like:

#include <iostream>
using namespace std;

class C {
public:
    int x;
};

class B {
public:
    ~B(){};
    virtual void doSomething() = 0;
};

class ConcreteB : public B{
public:
    ConcreteB(C c) : m_c(c) {}
    void doSomething(){
        std::cout << "HelloWorld" << std::endl;
    }
private:
    C m_c;
};
class A{
public:
    A(B *b): m_b(b){}

    void functionToTestWithSideEffect(){
        m_b->doSomething();
    }
private:
    B *m_b;

};

//#include <gmock/gmock.h>

int main() {
    C c;
    c.x = 42;
    ConcreteB b(c);
    A a(&b);
    a.functionToTestWithSideEffect();
    return 0;
}

In your tests you create a mock B which does not rely on any class C. Then you are only testing the interface with B. In this way you break A's dependency on C. Creating a mock B that doesn't depend on C is pretty simple:

class MockB : public B {
 public:
  MOCK_METHOD0(doSomething, void());
};
查看更多
登录 后发表回答