Собственно, у меня есть класс презентера, который из ApplicationContext вытаскивает пару других (подчиненных) презентеров. Мне бы не хотелось в конфигурации родительского презентера сразу прописывать эти дочерние призентеры, т.к. при инициализации презентера создается окно.
Как протестировать класс, который реализует IApplicationContextAware?
Лучший ответ:
Можно вместо объекта ApplicationContext
подсунуть тестируемому классу заглушку и в методе теста настраивать заглушку на соответствующие ожидания. Например что-то в этом роде:
[TestFixture]
public class PresenterTests
{
private Presenter _presenter; 1
private IApplicationContext _context; 2
private MockRepository _mockRepository;
[SetUp]
public void Init()
{
_mockRepository = new MockRepository();
_presenter = new Presenter(); 3
_context = _mockRepository.DynamicMock(); 4
_presenter.ApplicationContext = _context; 5
}
[Test]
public SomeMetod_SomeFacts_SomeExpectations() 6
{
_context.Expect(c => c.GetObject("firstObjectId")).Return(fakeFirstObject);
_context.Expect(c => c.GetObject("firstSecondId")).Return(fakeSecondObject);
// Логика теста
}
}
Класс теста хранит ссылку на тестируемый объект 1 и на заглушку контекста 2. Перед каждым тестом объект presenter создается заново 3, а контекст создается как заглушка 4 (в примере Rhino Mocks). Потом, в presenter передается созданный контекст-заглушка 5. В конкретном тесте 6 нам нужно только настроить заглушку контекста так, чтобы по запросу объектов она возвращала какие-нибудь реализации. Это тоже могут быть заглушки Rhino Mocks или собственные mock/stub-классы.
Вот есть на хабре статья
Новые ответы
Техника приведенная в комментариях к вопросу тоже имеет право на существование.
private IChildPresenter childPresenter;
public IChildPresenter ChildPresenter
{
get
{
if (childPresenter == null)
childPresenter = ApplicationContext.GetInstance<IChildPresenter>();
return childPresenter;
}
set { childPresenter = value; }
}
То есть если зависимость определена — возвращаем её, в противном случае — достаем зависимость из ioc-контейнера (который в этом случае работает как сервис-локатор). Особенно часто такая техника применяется для объектов, которым нельзя подсунуть зависимости во время выполнения программы, но можно во время тестирования. Классический пример — инъекция зависимостей в атрибуты. В runtime атрибуты создаются автоматически и нет возможности инъекции собственных зависимостей, а в классе теста можно легко самому инстанцировать объект атрибута и передать ему все, что нужно. Поэтому атрибуту делают 2 конструктора — один без параметров, а другой со всеми нужными зависимостями. Причем во время выполнения, если атрибуту не задана какая-то зависимость, то он сам «лезет» за ней в ioc-контейнер.
Вот пример:
public class MyAttribute : Attribute
{
private Dependency _dependency;
// Этот конструктор используется в runtime
public MyAttribute(){}
// Этот конструктор используем мы сами во время тестирования
public MyAttribute(Dependency dependency)
{
_dependency = dependency;
}
protected Dependency
{
get
{
// Если зависимость не задана, то дастаем ее из контейнера
if (_dependency == null)
return ServiceLocator.Get<Dependency>()
return _dependency;
}
}
}
Возникает соблазн для дочерних презентеров написать что-то вот такое:
Тогда при тестировании можно заглушку вставить будет. Но это как-то... не по-людски...
p.s. 500 символов для комментария - маловато.