【问题标题】:How to unit test Singleton class - C++?如何对 Singleton 类进行单元测试 - C++?
【发布时间】:2012-02-29 18:46:51
【问题描述】:

在 C++ 中对单例模式进行单元测试的方法有哪些? (请举例)

【问题讨论】:

  • 这看起来像是两个相当独立的问题。也许您可以将依赖注入部分移到一个新问题中?
  • @GeorgFritzsche 依赖注入据说是一种单元测试的方式,不是吗?
  • “将单例注入...”和“对单例进行单元测试”是两个不同的主题。
  • @GeorgFritzsche 链接说“依赖注入据说是单元测试的一种方式”,是不是错了?
  • @GeorgFritzsche 已编辑问题。 :)

标签: c++ oop design-patterns


【解决方案1】:

使单例的实现成为一个单独的类,并在外面制作一个实现“单例”的包装器。这样您就可以随心所欲地测试实现(除了琐碎且不必要的单例行为。

class SingletonImpl {
public:
  int doit(double,double);
};

class Singleton {
public:
  Singleton& instance() {...}
  int doit(double a,double b) {impl->doit(a,b);}
  ...
private:
  SingletonImpl impl;
}
【解决方案2】:

假设我们有经典的单例反模式,它负责三件事:

class Singleton {
public:
    // Globally accessible instance
    static Singleton & instance();

    // Public interface
    void do_something();

private:
    // Lifetime management
    Singleton();
    ~Singleton();
}

还有一个依赖于此的类:

class Dependent {
public:
    Dependent() : s(Singleton::instance()) {}

    void do_something_else();

private:
    Singleton & s;
};

现在我们想为单例编写一个单元测试:

void test_singleton() {
    Singleton s;        // Problem 1
    s.do_something();
    assert(/* some post-condition */);
}

对于依赖类:

struct StubSingleton : Singleton // Problem 2
{
    int did_something;

    StubSingleton : did_something(0) {}
    void do_something() {++did_something;}    
};

void test_dependent() {
    StubSingleton s;    // Problem 1
    Dependent d(s);     // Problem 3
    d.do_something_else();
    assert(s.did_something == 1);
}

我们看到需要克服三个问题:

  1. 我们无法在测试期间创建和销毁实例;
  2. 我们无法定义自己的子类来测试接口的使用方式;
  3. 我们无法向依赖类提供我们自己的依赖项。

解决这些问题的最简单方法是重构单例类:

  1. 将构造函数和析构函数公开,将生命周期管理的责任移出类;
  2. 使接口抽象,允许我们定义自己的实现;
  3. 删除全局实例,并修改依赖类以通过引用获取其依赖关系。

所以现在我们的类看起来像:

class Singleton {
public:
    virtual ~Singleton() {}
    virtual void do_something() = 0;
};

class RealSingleton : public Singleton
{
    void do_something();
};

class Dependent {
public:
    explicit Dependent(Singleton & s) : s(s) {}
    void do_something_else();
private:
    Singleton & s;
};

现在这个类很容易测试,并且几乎在生产中也很容易使用(你只需要创建一个RealSingleton 的实例并在需要的地方传递对它的引用)。唯一的问题是你不能再称它为单例了。

【讨论】:

  • 我会尽快跟进,在这里和你的其他答案。谢谢。
【解决方案3】:

我会这样做

class Singleton
{
    protected:
       static Singleton *instance = 0:
    public:
       Singleton &GetInstance()
       {
          if (!instance) instance = new Singleton;
          return *instance;
       }
       ...
};

然后为了测试我会创建只是为了测试目的

class TestSingleton : public Singleton
{
     public:
        void DestroyInstance() {
           if (instance) delete instance;
           instance = 0;
};

然后使用 TestSingleton - 这样您就可以执行所有测试用例并确保重新创建实例的开始。

【讨论】:

  • 你没有创建私有构造函数?
  • 那是 '...' 位 - 我以为你可以填写这些位。
  • 我以为你是故意的。
【解决方案4】:

单例只是一个类,你只能有一个实例。您如何找到该实例不是该模式的一部分,因此将 DI 与单例一起使用是完全可以的。

对单例模式进行单元测试很困难,这是反对使用它的主要论据之一。在 C++ 中执行此操作的一种方法是在单独的编译单元中定义单例,以便在测试使用单例的类时链接到模拟实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 2011-12-19
    • 2014-10-08
    • 2011-03-24
    相关资源
    最近更新 更多