Mocking C++ classes with dependency injection

别等时光非礼了梦想. 提交于 2020-01-11 07:06:48

问题


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.


回答1:


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());
};



回答2:


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:


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);


来源:https://stackoverflow.com/questions/5726580/mocking-c-classes-with-dependency-injection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!