Как выполнить юнит-тест класса Singleton - C ++? - PullRequest
5 голосов
/ 08 февраля 2012

Каковы способы модульного тестирования шаблона Singleton в C ++? (с примерами, пожалуйста)

Ответы [ 4 ]

11 голосов
/ 08 февраля 2012

Сделайте реализацию singleton отдельным классом и создайте оболочку, которая реализует "singletonness" снаружи. Таким образом, вы можете протестировать реализацию столько, сколько вам нужно (за исключением одноэлементного поведения, которое тривиально и не нужно.

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 голосов
/ 08 февраля 2012

Предположим, у нас есть классический одноэлементный анти-шаблон, который отвечает за три вещи:

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. Сделать конструктор и деструктор общедоступными, сняв с себя ответственность за управление временем жизни.the class;
  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 и передать ссылкитуда, где они нужны).Единственная проблема в том, что вы больше не можете называть это синглтоном.

1 голос
/ 08 февраля 2012

Вот как бы я это сделал

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, чтобы вы могли выполнить все тестовые случаи и убедиться, что это экземпляр, который запускается заново.

0 голосов
/ 08 февраля 2012

Синглтон - это просто класс, у которого вы можете иметь только один экземпляр. То, как вы находите этот экземпляр, не является частью этого паттерна, поэтому использование DI с синглтоном вполне подойдет.

Юнит-тестирование синглтон-паттерна сложно, это один из главных аргументов против его использования. Один из способов сделать это в C ++ - это определить синглтон в отдельном модуле компиляции, чтобы вы могли ссылаться на mock-реализацию при тестировании классов, использующих синглтон.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...