【问题标题】:Dynamically choose type of private member in class动态选择类中私有成员的类型
【发布时间】:2018-11-08 12:51:10
【问题描述】:

我无法理解这一点:我有一个名为 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,但这里的问题是基类还不知道对象的类型(真实或模拟)。此外,数据声明中也不允许使用“虚拟”,因此无论如何我尝试过之后都会遇到更多错误。

我在这里错过了什么?

【问题讨论】:

  • 进一步研究的有用术语:“依赖注入”
  • 谢谢。我查过那个。不知道那个词。

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


【解决方案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 将获取所提供对象的所有权(是它的接收器);这适合您的示例,而不是“始终执行”规则,它取决于用例,在其他情况下,共享指针(成员和参数)可能更合适。

【讨论】:

  • 非常感谢您的详尽回答。很有意思。 std::unique_ptr 对我来说是新的。我已尽力实现这一点,查看了有关该主题的许多其他网页,但还有一个问题;我如何将对象作为参数传递给构造函数?
  • @empewoow 最简单的:std::make_unique&lt;MyUsedClassReal&gt;(/*parameters for constructor*/)。请注意,将派生的智能指针分配给基的智能指针没有问题,这样就可以了。
  • 很抱歉我还是没听懂@Aconcagua。我有#included &lt;memory&gt; 然后我试过了:std::unique_ptr&lt;MyUsedClass&gt; base_ptr = std::make_unique&lt;MyUsedClassReal&gt;(); MyClass MyObject(base_ptr); 我得到了:error C2061: syntax error: identifier 'base_ptr' 我也试过了:MyClass MyObject(std::make_unique&lt;MyUsedClassReal&gt;()); 但仍然有两个错误:overloaded function "std::make_unique" is not a type nameerror C2061: syntax error: identifier 'make_unique' 我做错了什么?
  • std::unique_ptr 不能被复制(否则复制后指针不会是唯一的),所以你需要:MyClass myObject(std::move(base_ptr)); 注意我已经在构造函数中做了同样的事情。 std::make_unique 是 C++14。您是否启用了 C++14(或 C++17)?
  • 尝试您的最后一个解决方案后仍然会出现错误:overloaded function "std::move" is not a type nameC2061 syntax error: identifier 'move'。这很奇怪,因为它只在std::move 的最后一行失败,而使用它的另一行(MyClass::MyClass(std::unique_ptr&lt;MyUsedClass&gt; object) : myUsedObject(std::move(object)) {)没有失败。我使用的是 Visual Studio 2015,所以我认为它使用的是 Visual C++ 14.0。
猜你喜欢
  • 1970-01-01
  • 2011-02-24
  • 1970-01-01
  • 2014-09-02
  • 2015-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-30
相关资源
最近更新 更多