2009-04-23 3 views
2

У меня есть класс репозитория, который используется как минимум из двух других классов. Этот класс репозитория должен быть инициализирован - это очень дорого (запрос базы данных). Теперь я создаю отдельные экземпляры репозитория там, где мне это нужно. Дело в том, что каждый раз, когда я создаю репозиторий, он должен быть инициализирован. Как создать такой репозиторий для TDD? Первая вещь, на мой взгляд, была Синглтон, но это not the solution.TDD-friendly Singleton-like класс

+1

Можете ли вы объяснить, какие ограничения вы хотите получить в ответ, чтобы мы не уходили в долгу и тратили время на объяснение интерфейсов и насмехались над вами только для того, чтобы быть опущенным? –

+0

Это не относится к интерфейсам или Mocking. Это случай одиночной инициализации объекта и совместного использования этого объекта в приложении. – rafek

+1

И я не понимаю, что у меня вопрос. :( – rafek

ответ

1

Вы используете какой-либо контейнер IOC? Unity - мой контейнер выбора, и он содержит ContainerControledLifetimeManager, который делает ваш класс синглом, но не управляется самостоятельно.

1

Рассмотрите примеры кеширования для улучшения производительности, прежде чем рассматривать одиночные игры. Но для TDD-дружественных дизайнов учитывайте стратегическую инъекцию, чтобы «медленные» биты можно было удалить для тестирования и заменить на заглушки и издевки. Постарайтесь не делать вызовы db в тестах, если можете.

2

Один ответ для части TDD изучает насмешливость.

Заканчивать эту прекрасную статью Стивена Walther:

http://stephenwalther.com/blog/archive/2008/03/23/tdd-introduction-to-rhino-mocks.aspx

+1

Вниз избирателя. Объясните, почему. Не понял ли я вопрос? –

+0

Статья, которую вы предоставили, хороша, но ваш ответ это вопрос насчет насмешек. Мой вопрос касается дизайна. «Как создать, что я мог бы проверить его с помощью насмешек?» – rafek

+0

Фактически его answe r совершенно правильно –

3

Я надеюсь, что с помощью TDD людей вы имеете в виду 'проверяемым' код. Для Singleton ObjectX я считаю, что наиболее распространенным способом является разделение ответственности (SRP) на «управление созданием» на другой класс, поэтому ObjectX выполняет все, что он должен делать.

тогда у вас есть еще один класс ObjectXFactory или хост или что вы хотите назвать его, который отвечает за предоставление одного экземпляра для всех клиентов (и предоставление потоков синхронизации в случае необходимости и так далее)

  • Объект X может TDDed независимо. Вы можете создать новый экземпляр в вашем тестовом примере и проверить функциональность.
  • ObjectXFactory, с другой стороны, также легко проверить. Вам просто нужно увидеть, возвращают ли несколько вызовов GetInstance() один и тот же объект. ИЛИ лучше делегировать эту ответственность на рамках МОК, как Spring, которая позволяет декларативно знак определение объекта для получения одноплодной поведения (Вы сэкономите усилие написания тестов, а)

Вам просто нужно обучать и соответствовать к Командное соглашение о том, что конструктор ObjectX не нужно вызывать - всегда используйте ObjectXFactory.CreateInstance(). (Если вы обнаружите, что у вас есть проблема осознания/дисциплины, отмечают CTOR ObjectX в качестве внутренней и видна только в тестовой сборке с помощью подлый InternalsVisibleToAttribute) НТН

1

Вы не можете сделать что - по крайней мере, не в истинный смысл TDD.

Опираясь на стратегии DI/IoC, такие как Unity, ваши тесты зависят от внешнего компонента и не тестируются изолированно.

Затем тесты становятся интеграционными испытаниями, а не модульными испытаниями.

== Игнорировать ответ ниже здесь ==

Я предполагаю, что вы хотели знать, как сделать Repository проверяемым.

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

Я Проиллюстрируем это Rhino Mocks 3.5 for .NET 3.5:

Давайте сделать интерфейс из Repository, давайте называть это IRepository

public interface IRepository 
{ 
} 

Теперь, так как вам нужно использовать IRepository для двух различных объектов, то давайте просто используйте дженерики, чтобы вы могли создать экземпляр своего хранилища с этим:

public interface IRepository<T> 

Конечно, это означало бы что вы бы иметь какое-то метод найти:

{ 
    public IEnumerable<T> Find(Criteria criteria) 
} 

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

Теперь у вас есть объект:

public class SomeObject 
{ 
    IRepository<SomeObject> repository; 

    public SomeObject(){} 

    public IRepository<SomeObject> repository { get; set; } 

    IEnumerable<SomeObject> FindAll() 
    { 
     //let's assume new Criteria() will return all results 
     return respository.Find(new Criteria()); 
    } 
} 

Вы хотите, чтобы проверить SomeObject таким образом, что FindAll() будет возвращать ожидаемый набор результатов - это где Rhino Mocks придет в:

[TestFixture] 
public class SomeObjectTests 
{ 
    [Test] 
    public void TestSomeObjectFindAll() 
    { 
     IRepository<SomeObject> stubRepository = MockRepsitory.GenerateStub<IRepsitory<SomeObject>>(); 

     stubRepository.Expect(r => r.Find(new Criteria()) 
      .Return(new List<SomeObject>{ 
         new SomeObject(), 
         new SomeObject(), 
         new SomeObject()); 

     var testObject = new SomeObject { Repository = stubRepository }; 
     IList<SomeObject> findAllResult = testObject.FindAll(); 

     //returned list contains 3 elements, as expected above 
     Assert.AreEqual(3, findAllResult.Count) 
    } 
} 

Обратите внимание, что приведенный выше код не является лучшей практикой TDD во всех отношениях, но это место для начала.

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

Существует более полный пример и лучшие примеры на Ben Hall's article on Rhino Mocks.

+0

То же самое с ответом. – rafek

+0

Разве вы не понимаете, что я действительно ответил на ваш вопрос? Разве вы не читали ту часть, на которой я ответил, что вам нужно использовать интерфейсы? Неужели это наша вина, если вам не нравится слышать насмешку? –

+0

Это не тот случай. Я люблю насмехаться. Проблема заключалась в том, как реализовать репозиторий, который действует как Singleton, но можно проверить. – rafek

Смежные вопросы