Dovrò essere in disaccordo con entrambe le risposte. TheCodeKing, è del tutto legittimo utilizzare direttamente l'interfaccia IoC. Un esempio potrebbe essere una fabbrica di controller nel progetto ASP.NET - dove si potrebbe fare una risoluzione non banale usando più metodi nell'interfaccia
IUnityContainer
.
Hmm ... con labdas per l'iniezione automatica, non è mai necessario testare l'interfaccia IoC direttamente. Potresti semplicemente passare un lambda e verificare che venga chiamato con i parametri corretti.
Budda, si dovrebbe mai inserire un contenitore di IoC nel test dell'unità. Le dipendenze devono essere iniettate manualmente.
Di seguito è la soluzione che utilizzo. Fondamentalmente ho creato uno strato di astrazione su IUnityContainer
e ho implementato una semplice classe che delega a IUnityContainer
. Poiché la mia interfaccia non contiene metodi di estensione, posso facilmente deriderla.
public interface IDIContainer {
void RegisterType<TFrom>() where TFrom : class;
void RegisterType<TFrom, TTo>() where TTo : TFrom;
void RegisterType<TFrom, TTo>(string name) where TTo : TFrom;
void RegisterType(Type from, Type to);
void RegisterType(Type from, Type to, string name);
void RegisterInstance<TFrom>(TFrom instance) where TFrom : class;
T Resolve<T>();
T Resolve<T>(string name);
IEnumerable<T> ResolveAll<T>();
bool IsRegistered<TFrom>(string name) where TFrom : class;
bool IsRegistered<TFrom>() where TFrom : class;
}
public class DIContainer : IDIContainer {
IUnityContainer m_Container = new UnityContainer();
#region IDIContainer Members
public void RegisterType<TFrom>() where TFrom : class {
m_Container.RegisterType<TFrom>();
}
public void RegisterType<TFrom, TTo>() where TTo : TFrom {
m_Container.RegisterType<TFrom, TTo>();
}
public void RegisterType<TFrom, TTo>(string name) where TTo : TFrom {
m_Container.RegisterType<TFrom, TTo>(name);
}
public void RegisterType(Type from, Type to) {
m_Container.RegisterType(from, to);
}
public void RegisterType(Type from, Type to, string name) {
m_Container.RegisterType(from, to, name);
}
public void RegisterInstance<TFrom>(TFrom instance) where TFrom : class {
m_Container.RegisterInstance<TFrom>(instance);
}
public T Resolve<T>() {
return m_Container.Resolve<T>();
}
public IEnumerable<T> ResolveAll<T>() {
return m_Container.ResolveAll<T>();
}
public T Resolve<T>(string name) {
return m_Container.Resolve<T>(name);
}
public bool IsRegistered<TFrom>(string name) where TFrom : class {
return m_Container.IsRegistered<TFrom>(name);
}
public bool IsRegistered<TFrom>() where TFrom : class {
return m_Container.IsRegistered<TFrom>();
}
#endregion
}
Ora, riscrivere la classe da utilizzare IDIContainer
:
public class MyManager
{
public MyManager(IDIContainer container) : base(container) { }
public IResult DoJob(IData data)
{
IMyLog log = MyContainer.Resolve<IMyLog>();
... use log.Id ...
MyContainer.Resolve<...>();//usage for other purposes...
}
}
e riscrivere il test di unità in questo modo:
[TestClass]
public class Test {
[TestMethod]
public void TestDoJob() {
Mock<IMyLog> mockLog = new Mock<IMyLog>();
Mock<IDIContainer> containerMock = new Mock<IDIContainer>();
//Setup mock container to return a log mock we set up earlier
containerMock.Setup(c=>c.Resolve<IMyLog>()),Returns(mockLog);
//Verify that all setups have been performed
containerMock.VerifyAll();
}
}
Le dipendenze sul contenitore IoC sono un antipattern. Prova a limitare il contenitore a una classe di livello superiore e fargli creare altri oggetti. Come suggerisce @TheCodeKing, le auto-fabbriche possono aiutare. Vedi http://kozmic.pl/2010/06/20/how-i-use-inversion-of-control-containers/ – TrueWill