0

У меня есть приложение, использующее Unity для DI, но во время написания модульных тестов я столкнулся с некоторой проблемой. В нескольких моих методов бизнес-уровня у меня есть код, который похож на это:Unit Testing IUnityContainer.Resolve

var obj = container.Resolve<ISomeObj>(); 

Это либо стоя в оперативной памяти объект, который будет в конечном счете, будет передан прочь к базе данных, или она является не- который в конечном итоге будет передан клиенту. Проблема, однако, что RhinoMocks является (по-видимому) не может издеваться контейнер правильно так делать что-то вроде этого:

mockContainer = MockRepository.GenerateMock<IUnityContainer>(); 
mockContainer.Expect(x => x.Resolve<ISomeObj>()) 
      .Return(mockObj); 

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

Любые мысли или предложения приветствуются!

---- EDIT ----

С Якубом опубликовал свой ответ я делал некоторое чтение о Service Locator (анти) Pattern и в то время как он, кажется, принято считать, что это антипаттерны , Я не нашел ответа о том, что делать с POCOs.

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

public class Foo() 
{ 
    private ISomeObj someObj; 
    public Foo(ISomeObj injectObj) 
    { 
     someObj = injectObj; 
    } 
} 

Я полагаю, что моя единственная жалоба с этим подходом является то, что он (потенциально) сделать конструктор «занят» ала:

public class Foo() 
{ 
    public Foo(ISomeService injectSvc, ISomeObj injectObj, ISomeObj2 injectObj2, ISomeObj3 injectObj3) 
    { 
     ... 
    } 
} 

Кроме того, если я не хватает чего-то, я должен был бы способ повторной инициализации данного экземпляра для повторного использования. Значение: если MethodA() и MethodB() оба потребляют ISomeObj, когда MethodA() заканчивается с ISomeObj, мне нужно было бы каким-то образом повторно инициализировать все поля в ISomeObj, чтобы MethodB() мог выполнять свою работу.

Каков наилучший способ решения этой проблемы?

+1

Не используйте контейнеры DI для модульных испытаний: http://stackoverflow.com/a/1465896/126014 –

ответ

5

Что вы делаете (разрешая объекты с использованием контейнера из методов вашего бизнес-уровня) называется Service Location и is considered an anti-pattern. Возможно, вы захотите рассмотреть возможность реорганизации для использования Constructor Injection. И если вы это сделаете, вам не нужно будет использовать контейнер в своих модульных тестах.

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

container.RegisterInstance<ISomeObj>(mockObj); //mockObj is the mocking object that implements ISomeObj 

Все операции разрешать сделали для этого интерфейса (ISomeObj) будет возвращать тот же экземпляр.

Если вам нужно, чтобы быть в состоянии получить новый экземпляр для каждой операции решимости, вы можете сделать следующее:

container.RegisterType<ISomeObj>(new InjectionFactory(x => GenerateMock())); 

Где GenerateMock метод, который создает фиктивный объект. Вы можете заменить этот вызов кодом, создающим макет с помощью RhinoMocks.