Tôi sẽ phải không đồng ý với cả hai câu trả lời. TheCodeKing, hoàn toàn hợp pháp để sử dụng giao diện IoC trực tiếp. Một ví dụ có thể là một nhà máy điều khiển trong dự án ASP.NET - nơi mà một người có thể thực hiện độ phân giải không tầm thường bằng nhiều phương thức trên giao diện
IUnityContainer
.
Hmm ... với labdas tiêm tự động tại nhà máy, người ta không bao giờ phải kiểm tra trực tiếp giao diện IoC. Bạn chỉ có thể vượt qua một lambda và xác minh rằng nó được gọi với các tham số đúng.
Bạn, bạn nên không bao giờ mang theo một thùng chứa IoC vào thử nghiệm đơn vị của bạn. Các phụ thuộc phải được tiêm thủ công.
Dưới đây là giải pháp tôi sử dụng. Về cơ bản, tôi đã tạo một lớp trừu tượng trên IUnityContainer
và triển khai một lớp đơn giản ủy quyền cho IUnityContainer
. Bởi vì giao diện của tôi không chứa các phương thức mở rộng, tôi có thể dễ dàng giả lập nó.
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
}
Bây giờ, viết lại lớp học của bạn để sử dụng 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...
}
}
Và viết lại bài kiểm tra đơn vị như sau:
[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();
}
}
Phụ thuộc vào thùng chứa IoC là một mẫu giả. Cố gắng hạn chế vùng chứa ở một cấp cao nhất và tạo nó cho các đối tượng khác của bạn. Như @ TheCodeKing đề xuất, các nhà máy tự động có thể trợ giúp. Xem http://kozmic.pl/2010/06/20/how-i-use-inversion-of-control-containers/ – TrueWill