动态选择班级中私人成员的类型

时间:2018-11-08 12:51:11

标签: c++ unit-testing types mocking private-members

我无法解决这个问题:我有一个名为MyClass的类,该类具有MyUsedClass类型的私有成员。为了创建单元测试,我有一个MyUsedClass的模拟(模拟)版本。我想用模拟的MyUsedClass私有成员或MyUsedClass的真正私有成员动态调用MyClass。因为我想动态地调用它,所以无法使用#defines和#ifdefs。

基本上我想做这样的事情:

class MyClass {
    public:
        MyClass(bool mock = false) {}; // Default bool to false.
        ~MyClass(void) {};
        void DoSomething(void) { /* Do something with MyUsedObject here... */ };
        void DoMore(void);
        ...
    private:
        if (mock) {
            MyUsedClassMock MyUsedObject;
        } else {
            MyUsedClassReal MyUsedObject;
        }
};

MyClass MyObject; // Create default instance with real MyUsedObject.
MyClass MyObject(true); // Create instance with the mock MyUsedObject.

但是这当然不起作用,因为如果类定义中的if语句无法执行。

另一种方法是使用多态性并创建基类,真实类和模拟类。基类将具有所有功能的所有实现,并且通过选择调用MyClass的真实版本或模拟版本,我可以选择MyUsedObject的类型。

class MyClassBase {
    public:
        MyClassBase(void) {};
        ~MyClassBase(void) {};
        void DoSomething(void) { /* Do something with MyUsedObject here... */ };
        void DoMore(void);
        ...
    private:
        // No MyUsedObject in the Base class.
};

class MyClassReal : public MyClassBase {
    public:
        MyClassReal(void) {};
        ~MyClassReal(void) {};
    private:
        MyUsedClassReal MyUsedObject; // Here is MyUsedObject created, but then "Real".
};

class MyClassMock : public MyClassBase {
    public:
        MyClassMock(void) {};
        ~MyClassMock(void) {};
    private:
        MyUsedClassMock MyUsedObject; // Here is MyUsedObject created, but then "Mock".
};

MyClassReal MyObject; // Create instance with the real MyUsedObject.
MyClassMock MyObject; // Create instance with the mock MyUsedObject.

不幸的是,这也行不通,因为MyClassBase函数实现对MyUsedObject尚不了解,所以我在这里遇到错误。一种想法是用来在基类中创建虚拟MyUsedObject,但是这里的问题是基类尚不知道对象的类型(真实或模拟)。此外,数据声明中不允许使用“虚拟”,因此无论如何尝试再次获得更多错误。

我在这里想念什么?

1 个答案:

答案 0 :(得分:1)

多态方法是必经之路。但是,您必须提出不同的建议:

class MyUsedClass { }; // the base class, having (pure?) virtual functions
class MyUsedClassReal : public MyUsedClass { }; // provides real functionality
class MyUsedClassMock : public MyUsedClass { }; // mocks the functionality

派生类将提供实际场景和模拟时特别需要的实现。您自己的类现在将动态地使用一个或另一个:

class MyClass
{
public:
    MyClass(bool mock = false)
    ~MyClass(void) {};
    void doSomething();
private:
    std::unique_ptr<MyUsedClass> myUsedObject;
};

MyClass::MyClass(bool mock)
    : myUsedObject(mock ? new MyUsedClassMock() : new MyUsedClassReal())
{ }

void MyClass::doSomething() { /* use the pointer! */ };

如果您遵循StoryTeller的提示(“依赖注入”),则会将对象作为参数传递给构造函数,而不是在内部创建它,这可能是更可取的:

MyClass::MyClass(std::unique_ptr<MyUsedClass> object)
    : myUsedObject(std::move(object))
{ }

也有一个std::unique_ptr作为参数,很明显MyClass将获得所提供对象的所有权(是它的接收器);这适用于您的示例,而不是“总是执行”规则,它取决于用例,在其他情况下,共享指针(成员和参数)可能更合适。