Тестирование синглетонов и создание подклассов - PullRequest
6 голосов
/ 04 августа 2011

Я видел это при использовании пикоконтейнера.Они говорят, что вы должны избегать одиночных игр.потому что паттерн Singleton делает практически невозможным тестирование класса (и, возможно, всех других классов, которые от него зависят).Очень трудно создать подкласс или создать фиктивный объект для класса Singleton.

Но если вам это абсолютно необходимо, есть ли решение проблемы с тестированием и подклассами?

Ответы [ 3 ]

5 голосов
/ 04 августа 2011

Что затрудняет тестирование синглетонов, так это код, обеспечивающий их одноэлементность (т. Е. Шаблон public static MySingleton getInstance() {...}). Использование контейнера с инверсией управления, такого как Picocontainer, Guice или Spring, удаляет это беспокойство с объекта, поэтому теперь:

  • Его можно создать и подключить к нему соавторов в тестах без проблем.

  • Код, вызывающий синглтон, не должен знать, какой класс он ищет (что ему нужно знать, если бы он вызывал статический метод).

Я интерпретирую совет на сайте picocontainer как похожий на этот. Они говорят вам: позвольте нашему контейнеру управлять областью ваших компонентов за вас, не привязывайте к ним код, обеспечивающий область действия.

1 голос
/ 04 августа 2011

Использование IOC (инверсия управления) вместо синглетонов, инициируемых при первом использовании, также выгодно и по другим причинам.

Singleton-инициализация может страдать (как известно) из-за проблем с многопоточностью, когда два потока пытаются получить к ней доступ одновременно. Последующий доступ, вероятно, будет правильно синхронизирован, но сделать первый будет гораздо сложнее.

Еще одно огромное преимущество использования IOC, которое я обнаружил, - это когда при инициализации может произойти ошибка. Вы не хотите, чтобы это происходило при «первом использовании», вы хотите знать об этой ошибке на ранней стадии, и, конечно, проще обрабатывать ошибку таким способом.

Наконец, что касается тестирования, IOC предоставляет идеальную модель для изоляции компонентов, замены их по мере необходимости и более гибкого объединения различных комбинаций, обеспечивая тем самым идеальное использование как для модульного тестирования, так и для интеграционного тестирования. как хороший механизм отката без необходимости вообще возвращать какой-либо код.

Общая причина, по которой так часто используются синглтоны, не для единства, а для глобальности. Если ваш проект управляется правильно, у вас есть один глобальный объект, на который «регистрируются» все остальные (таким образом, ваша модель IOC зависает от него), и они доступны глобально, но все еще настраиваются.

1 голос
/ 04 августа 2011

Если вы должны иметь синглетоны:

  1. Иметь интерфейс, описывающий каждый синглтон
  2. Доступ к вашим синглетам из глобального / синглтона ServiceLocator
  3. Переключение экземпляров, зарегистрированных в ServiceLocator во время тестирования

Пример:

interface IBankApi
{
   public void MakeDeposity(int accountNumber, int dollarAmount);
   // ...
}

public class RealBankApi : IBankApi { ... }

// startup code
serviceLocator.Register<IBankApi>(new RealBankApi());

// code using the API
serviceLocator.Resolve<IBankApi>().MakeDeposit(...);

// test code setup
class FakeBankApi : IBankApi { ... }
serviceLocator.Register<IBankApi>(new FakeBankApi());
...