Как изолировать синглтон в моих модульных тестах? - PullRequest
1 голос
/ 28 августа 2011

У меня есть статический класс в моей программе. В статическом конструкторе я создаю экземпляр сервиса. Прокси службы - синглтон.

Я должен написать модульные тесты для этого класса, и, конечно, я хочу изолировать этот сервис. Как я могу это сделать?

В моем проекте мы используем Rhino.Mocks.

Ответы [ 2 ]

3 голосов
/ 28 августа 2011

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

class MyClass()
{
   public MyClass()
   {
      var myService = StaticFoo.MyServiceInstance;
   }
}

Это эквивалентно созданию конкретного экземпляра класса локально, поскольку знание того, «как добраться» до вашего Singleton, является частьюВаша реализация класса.Что вам нужно будет сделать, это удалить эти знания и внедрить эту зависимость так же, как вы вводите другие зависимости от не-синглетонов.Самым простым способом было бы внедрение конструктора:

class MyClass()
{
   public MyClass(IService myService)
   {
     //..
   }
}

Другая необходимая часть - это либо убедиться, что все методы / свойства интерфейса в вашем сервисе определены как виртуальные, либо определить интерфейс или абстрактный базовый класс, который ваш сервисреализует и определяет все операции, которые ваш класс MyClass использует с этим сервисом.Это необходимо, поскольку большинство фреймворков для модульного тестирования (включая Rhino-Mocks) могут только макетировать виртуальные методы / свойства.

Альтернатива, которую я видел, но лично мне не очень нравится, - это установка сеттера в вашем синглтоне, чтобы вы моглиможет "поменять" конкретный класс с вашим фиктивным объектом, необходимым для модульного тестирования.Этот установщик будет использоваться только для модульного тестирования и может быть помечен как внутренний, чтобы классы вне вашей сборки не имели доступа.Затем вы можете использовать атрибут InternalsVisibleTo, чтобы сделать специальное исключение для вашей сборки модульного тестирования, чтобы он мог видеть и использовать установщик.

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

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

В вашем классе должен быть публичный метод инициализации, который принимает экземпляр службы. Затем вы можете ввести фиктивный объект, используя метод инициализации.

...