Как лучше тестировать синглетон?
От: AlexNek  
Дата: 17.03.12 14:49
Оценка:
Есть синглетон и юнит тесты к нему.
Каждый тест проверяет какую либо часть класса синглетона, косвенно предполагая что синглтон создался перед тестом.
Когда тесты выполняются путем индивидуального вызова каждого теста — все нормально.
Однако когда тесты выполняются в группе, происходят различные накладки связанные с изменением статуса синглтона предыдущими тестами.
Рещить проблему довольно просто добавив в синглтон метод "Установить первоначальное состояние", однако этот метод требуется исключительно для тестирования, в реальном использовании его нельзя никогда вызывать.
Можно еще запускать каждый тест всегда в отдельном потоке, но неясно как это сделать красиво, к чему это приведет при тестировании, да и нужно будет для всего проекта несколько сотен тестов править.
Главная дилемма:править код ради тестов или извращаться с тестами?
Cообщение написано в << RSDN@Home 1.2.0 alpha 5-AN-R8 rev. 13227>>
Re: Как лучше тестировать синглетон?
От: dimgel Россия https://github.com/dimgel
Дата: 17.03.12 14:58
Оценка:
Здравствуйте, AlexNek,

Я на скале (там объект-синглтон отличается от класса ключевым словом — "object" вместо "class"; для "object C" неявно создаётся класс C$) делаю так:

class C protected(dependencies) { 
    ... 
}
object C extends C(default-runtime-dependencies)


А для тестов создаю экземпляр так:

new C(mock-dependencies)
Re[2]: Как лучше тестировать синглетон?
От: dimgel Россия https://github.com/dimgel
Дата: 17.03.12 15:00
Оценка:
Здравствуйте, dimgel, Вы писали:

D>class C protected(dependencies)

D>new C(mock-dependencies)

Блин, не так. Конструктор-то protected. Создаётся пустой

class C4Test(dependencies) extends C(dependencies)


как раз обходящий protected-конструктор, и уже ему передаются mock-зависимости.
Re: Как лучше тестировать синглетон?
От: okman Беларусь https://searchinform.ru/
Дата: 17.03.12 15:09
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>Есть синглетон и юнит тесты к нему.

AN>Каждый тест проверяет какую либо часть класса синглетона, косвенно предполагая что синглтон создался перед тестом.
AN>Когда тесты выполняются путем индивидуального вызова каждого теста — все нормально.
AN>Однако когда тесты выполняются в группе, происходят различные накладки связанные с изменением статуса синглтона предыдущими тестами.
AN>Рещить проблему довольно просто добавив в синглтон метод "Установить первоначальное состояние", однако этот метод требуется исключительно для тестирования, в реальном использовании его нельзя никогда вызывать.
AN>Можно еще запускать каждый тест всегда в отдельном потоке, но неясно как это сделать красиво, к чему это приведет при тестировании, да и нужно будет для всего проекта несколько сотен тестов править.
AN>Главная дилемма:править код ради тестов или извращаться с тестами?

Можно поместить синглтон в динамическую библиотеку, а затем вызывать LoadLibrary/TestSingleton/FreeLibrary.
Можно сделать пару шаблонных методов setup/teardown специально для тестов — поскольку они
шаблонные, то в релиз не попадут, ибо вызываться не будут.

Кстати, а почему тестируется именно синглтон, а не сам объект, который "синглтонится" ?
И не стоит ли их разделить и тестировать по отдельности ?
Re: Как лучше тестировать синглетон?
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 17.03.12 15:17
Оценка: +1
AN>Главная дилемма:править код ради тестов или извращаться с тестами?

Стандартый способ — это разработка синглетона, как обычного instance-класса, который "замыкается в синглетон-переменную".
Это позволяет один и тот же код, использовать и как singleton, и как не singleton.

И в тестах поведение синглетона тестируется так же, как тестируется обычный класс, а не как синглетон.
Re[2]: Как лучше тестировать синглетон?
От: AlexNek  
Дата: 17.03.12 15:33
Оценка:
Здравствуйте, dimgel, Вы писали:

D>Здравствуйте, AlexNek,


D>Я на скале (там объект-синглтон отличается от класса ключевым словом — "object" вместо "class"; для "object C" неявно создаётся класс C$) делаю так:


D>
D>class C protected(dependencies) { 
D>    ... 
D>}
D>object C extends C(default-runtime-dependencies)
D>


D>А для тестов создаю экземпляр так:


D>
D>new C(mock-dependencies)
D>

К сожалению, требуется для С# (NET 2.0), да и отделять класс от синглтона совсем не хочется (хотя класс просто наследуется от "синглтон темплейт"), тогда не будут работать "стандартные вызовы" используемые в программе и тестах.
Cообщение написано в << RSDN@Home 1.2.0 alpha 5-AN-R8 rev. 13227>>
Re: Как лучше тестировать синглетон?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 17.03.12 15:40
Оценка: 1 (1) +2
Здравствуйте, AlexNek, Вы писали:

AN>Главная дилемма:править код ради тестов или извращаться с тестами?


Единственный нормальный способ — выкинуть синглтон нафик. Если же есть желание поизвращаться и речь про дотнет — создавай на каждый тест отдельный аппдомен.
... << RSDN@Home 1.2.0 alpha 5 rev. 27 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[2]: Как лучше тестировать синглетон?
От: AlexNek  
Дата: 17.03.12 16:28
Оценка:
Здравствуйте, okman, Вы писали:

O>Здравствуйте, AlexNek, Вы писали:


AN>>Есть синглетон и юнит тесты к нему.

AN>>Каждый тест проверяет какую либо часть класса синглетона, косвенно предполагая что синглтон создался перед тестом.
AN>>Когда тесты выполняются путем индивидуального вызова каждого теста — все нормально.
AN>>Однако когда тесты выполняются в группе, происходят различные накладки связанные с изменением статуса синглтона предыдущими тестами.
AN>>Рещить проблему довольно просто добавив в синглтон метод "Установить первоначальное состояние", однако этот метод требуется исключительно для тестирования, в реальном использовании его нельзя никогда вызывать.
AN>>Можно еще запускать каждый тест всегда в отдельном потоке, но неясно как это сделать красиво, к чему это приведет при тестировании, да и нужно будет для всего проекта несколько сотен тестов править.
AN>>Главная дилемма:править код ради тестов или извращаться с тестами?

O>Можно поместить синглтон в динамическую библиотеку, а затем вызывать LoadLibrary/TestSingleton/FreeLibrary.

O>Можно сделать пару шаблонных методов setup/teardown специально для тестов
Дя шарпа generic функция с фиктивным параметром? Можно ее еще интернал сделать — пожалуй подойдет.
O>- поскольку они шаблонные, то в релиз не попадут, ибо вызываться не будут.

O>Кстати, а почему тестируется именно синглтон, а не сам объект, который "синглтонится" ?

Тут видимо различия в терминологии и краткости описания. Речь идет о реальном объекте который подчиняется концепту синглтона.
O>И не стоит ли их разделить и тестировать по отдельности ?
Реальный класс просто наследуется от шаблона синглтона. Так что в принципе можно было бы разделить. Но как потом запретить использовать класс "просто так". Да и как потом тестировать другие классы использующие данный синглтон? Вполне может быть идентичная проблема.
Cообщение написано в &lt;&lt; RSDN@Home 1.2.0 alpha 5-AN-R8 rev. 13227&gt;&gt;
Re[2]: Как лучше тестировать синглетон?
От: AlexNek  
Дата: 17.03.12 16:28
Оценка:
Здравствуйте, DarkGray, Вы писали:

AN>>Главная дилемма:править код ради тестов или извращаться с тестами?


DG>Стандартый способ — это разработка синглетона, как обычного instance-класса, который "замыкается в синглетон-переменную".

Что то не вижу "красивого решения", можно примерчик? В итоге требуется для шарпа, но для начала подойдет любой язык без "встроенного синглтона"
DG>Это позволяет один и тот же код, использовать и как singleton, и как не singleton.
Как это разрешить исключительно для тестов?
Cообщение написано в &lt;&lt; RSDN@Home 1.2.0 alpha 5-AN-R8 rev. 13227&gt;&gt;
Re[3]: Как лучше тестировать синглетон?
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 17.03.12 17:08
Оценка:
DG>>Стандартый способ — это разработка синглетона, как обычного instance-класса, который "замыкается в синглетон-переменную".
AN>Что то не вижу "красивого решения", можно примерчик? В итоге требуется для шарпа, но для начала подойдет любой язык без "встроенного синглтона"

class SingletonClass
{
  public void Method1(){}

  public static readonly SingletonClass Singleton = new SingletonClass();
}


использование как Singleton — SingletonClass.Singleton.Method1();
использование не как Singleton — new SingletonClass().Method1();

DG>>Это позволяет один и тот же код, использовать и как singleton, и как не singleton.

AN>Как это разрешить исключительно для тестов?

сделать конструктор SingletonClass-а protected, и в тестовой сборке сделать вспомогательный метод для создания класса
class SingletonClass
{
  protected SingletonClass(){}
  ..
}

SingletonClass CreateSingletonClass()
{
  return new SingletonClass2();
}
class SingletonClass2:SingletonClass{}
Re[3]: Как лучше тестировать синглетон?
От: okman Беларусь https://searchinform.ru/
Дата: 17.03.12 17:13
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>Что то не вижу "красивого решения", можно примерчик? В итоге требуется для шарпа, но для начала подойдет любой язык без "встроенного синглтона"


Возможно, красивого решения именно для синглтона и не существует.
Не даром он часто преподносится, как антипаттерн. Ведь класс-синглтон выполняет, по сути,
две функции — "родные" функции класса и функции ограничивания количества экземпляров.
Поэтому и тестировать его в большинстве случаев неудобно.

Еще, IMHO, наследоваться от синглтона неверно. Ведь это класс-одиночка, а наследники
будут связаны с ним отношениями "is-a". То есть, derived class is a base class, что
противоречит назначению синглтона.

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

Например в C++, имея стандартный синглтон Майерса и класс settings, подлежащий
вынесению в разряд одиночек, я бы написал тесты для шаблона singleton<>, юзающего
какой-нибудь специально созданный для этой цели mock-объект, проверяя единственность
экземпляра и инициализации, плюс, возможно, его потокобезопасность, а settings
тестировал отдельно, как обычный класс. Ну а потом набросал несколько тестов "на
интеграцию", то есть — использующих singleton<settings>. Как-то так, в общем.

Для .NET не в курсе, как там принято обходиться с синглтонами, но вообще отношение к
ним очень разное, от чуть ли не поклонения до беспощадной критики — http://rsdn.ru/forum/cpp/4652557.aspx
Автор:
Дата: 08.03.12
Re[4]: Как лучше тестировать синглетон?
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 17.03.12 17:14
Оценка:
так же класс с protected constructor-ом можно создать так:

SingletonClass CreateSingletonClass()
{
  return (SingletonClass)Activator.CreateInstance(typeof(SingletonClass), true);
}
Re[2]: Как лучше тестировать синглетон?
От: AlexNek  
Дата: 17.03.12 17:21
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, AlexNek, Вы писали:


AN>>Главная дилемма:править код ради тестов или извращаться с тестами?


AVK>Единственный нормальный способ — выкинуть синглтон нафик.

Нужно будет перелопачивать весь проект, не думаю что на это кто то пойдет. Но даже если и да, то что использовать взамен? Нужен объект к которому можно просто обратится из произвольного места программы.
AVK>Если же есть желание поизвращаться и речь про дотнет — создавай на каждый тест отдельный аппдомен.
Да речь про .НЕТ, главное сделать это в стартапе.
Cообщение написано в &lt;&lt; RSDN@Home 1.2.0 alpha 5-AN-R8 rev. 13227&gt;&gt;
Re[4]: Как лучше тестировать синглетон?
От: os24ever
Дата: 17.03.12 17:39
Оценка:
O>Возможно, красивого решения именно для синглтона и не существует.
O>Не даром он часто преподносится, как антипаттерн. Ведь класс-синглтон выполняет, по сути,
O>две функции — "родные" функции класса и функции ограничивания количества экземпляров.
O>Поэтому и тестировать его в большинстве случаев неудобно.

Скорее, вот по какой причине:
Число состояний синглтона = 2 в степени (количество внутренних переменных)
Число возможных последовательностей состояний = факториал от предыдущей величины.

Так что если у синглтона 10 внутренних переменных, то число тестов пропорционально факториалу от тысячи.
А если 20 переменных, то никакие тесты не спасут.

верую+в+ооп+ибо+истинно+ибо+верую+в+ооп
Re[3]: Как лучше тестировать синглетон?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 17.03.12 17:53
Оценка:
Здравствуйте, AlexNek, Вы писали:

AVK>>Единственный нормальный способ — выкинуть синглтон нафик.

AN>Нужно будет перелопачивать весь проект

Это полезно.

AN> Но даже если и да, то что использовать взамен?


Явную передачу контекста.
... << RSDN@Home 1.2.0 alpha 5 rev. 27 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[4]: Как лучше тестировать синглетон?
От: os24ever
Дата: 17.03.12 18:25
Оценка:
AN>> Но даже если и да, то что использовать взамен?
AVK>Явную передачу контекста.

Или, если уж совсем никак, сложить данные в БД и добавить прослойку в виде Indexed View.
indexed view
Re[4]: Как лучше тестировать синглетон?
От: AlexNek  
Дата: 17.03.12 21:52
Оценка:
Здравствуйте, DarkGray, Вы писали:

DG>>>Стандартый способ — это разработка синглетона, как обычного instance-класса, который "замыкается в синглетон-переменную".

AN>>Что то не вижу "красивого решения", можно примерчик? В итоге требуется для шарпа, но для начала подойдет любой язык без "встроенного синглтона"

DG>
DG>class SingletonClass
DG>{
DG>  public void Method1(){}

DG>  public static readonly SingletonClass Singleton = new SingletonClass();
DG>}
DG>


Здесь есть несколько моментов для нас:
— стояла задача простого превращения "любого" класса в синглтон одним и тем же универсальным способом, без модификации класса.
— нужна lazy instantiation.

Использум модифицированную 5 версию: Implementing the Singleton Pattern in C#

DG>использование как Singleton — SingletonClass.Singleton.Method1();

DG>использование не как Singleton — new SingletonClass().Method1();

DG>>>Это позволяет один и тот же код, использовать и как singleton, и как не singleton.

AN>>Как это разрешить исключительно для тестов?

DG>сделать конструктор SingletonClass-а protected,

По идее так и должно быть
DG>и в тестовой сборке сделать вспомогательный метод для создания класса

DG>
DG>class SingletonClass
DG>{
DG>  protected SingletonClass(){}
DG>  ..
DG>}

DG>SingletonClass CreateSingletonClass()
DG>{
DG>  return new SingletonClass2();
DG>}
DG>class SingletonClass2:SingletonClass{}

DG>

А что делать с тестами которые не используют синглтон напрямую?
Cообщение написано в &lt;&lt; RSDN@Home 1.2.0 alpha 5-AN-R8 rev. 13227&gt;&gt;
Re[4]: Как лучше тестировать синглетон?
От: AlexNek  
Дата: 17.03.12 21:52
Оценка:
Здравствуйте, okman, Вы писали:

O>Здравствуйте, AlexNek, Вы писали:


AN>>Что то не вижу "красивого решения", можно примерчик? В итоге требуется для шарпа, но для начала подойдет любой язык без "встроенного синглтона"


O>Возможно, красивого решения именно для синглтона и не существует.

O>Не даром он часто преподносится, как антипаттерн. Ведь класс-синглтон выполняет, по сути,
O>две функции — "родные" функции класса и функции ограничивания количества экземпляров.
O>Поэтому и тестировать его в большинстве случаев неудобно.

O>Еще, IMHO, наследоваться от синглтона неверно. Ведь это класс-одиночка, а наследники

O>будут связаны с ним отношениями "is-a". То есть, derived class is a base class, что
O>противоречит назначению синглтона.
"Наследование" выглядит следующим образом (более лучшего решения в то время не было найдено)
public class FrameworkManager : Singleton<FrameworkManager>, ISingletonInit
{
...
}

O>В общем, надо как-то извратиться и тестировать отдельно функции синглетона (как шаблона) и
O>функции класса, который упаковывается в синглтон (в Вашем случае — наследуется от шаблона
O>синглтона). То есть, писать тесты, которые тестируют одиночность класса и единственность
O>его инициализации (плюс, возможно, его потокобезопасность), и тесты, тестирующие сам класс.
Это свободно можно разделить использую дополнительный тествый класс, так как все остальные классы буду вести себя одинаковым образом.

O>Например в C++, имея стандартный синглтон Майерса и класс settings, подлежащий

O>вынесению в разряд одиночек, я бы написал тесты для шаблона singleton<>, юзающего
O>какой-нибудь специально созданный для этой цели mock-объект, проверяя единственность
O>экземпляра и инициализации, плюс, возможно, его потокобезопасность, а settings
O>тестировал отдельно, как обычный класс.
O>Ну а потом набросал несколько тестов "наинтеграцию", то есть — использующих singleton<settings>.
В этих-то тестах и проблема

O>Для .NET не в курсе, как там принято обходиться с синглтонами, но вообще отношение к

O>ним очень разное, от чуть ли не поклонения до беспощадной критики — http://rsdn.ru/forum/cpp/4652557.aspx
Автор:
Дата: 08.03.12
Cообщение написано в &lt;&lt; RSDN@Home 1.2.0 alpha 5-AN-R8 rev. 13227&gt;&gt;
Re[4]: Как лучше тестировать синглетон?
От: AlexNek  
Дата: 17.03.12 21:52
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, AlexNek, Вы писали:


AVK>>>Единственный нормальный способ — выкинуть синглтон нафик.

AN>>Нужно будет перелопачивать весь проект

AVK>Это полезно.

это если проект "для себя". Хотел бы я знать кто на работе позволит курочить рабочий проект "для красоты"

AN>> Но даже если и да, то что использовать взамен?


AVK>Явную передачу контекста.

То бишь, на всю иерархию всегда передавать чего то?
Cообщение написано в &lt;&lt; RSDN@Home 1.2.0 alpha 5-AN-R8 rev. 13227&gt;&gt;
Re[5]: Как лучше тестировать синглетон?
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 17.03.12 22:13
Оценка:
AN>А что делать с тестами которые не используют синглтон напрямую?

пересоздавать синглетон в начале каждого теста


void RecreateSingletonInSingletonClass()
{
  typeof(SingletonClass).GetField("Singleton", BindingFlags.Public | BindingFlags.Static)
    .SetValue(null, Activator.CreateInstance(typeof(SingletonClass), true))
}
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.