在一个类中,我使用以下代码:
public User CurrentUser
{
get
{
var unityContainer = new UnityContainer();
var httpContextHelper = unityContainer.Resolve<HttpContextHelper>();
return httpContextHelper.GetUser();
}
}
这是在Bootstrapper.cs
文件:
public static class Bootstrapper
{
public static void Initialise()
{
IUnityContainer unityContainer = new UnityContainer();
unityContainer.RegisterType<IHttpContextHelper, HttpContextHelper>();
DependencyResolver.SetResolver(new UnityDependencyResolver(unityContainer));
}
}
我不能在这里使用构造函数注入,因为它是一个基类,重构它需要相当多的工作。
但是我该如何对它进行单元测试呢?我找不到合适的方法来模拟unityContainer.Resolve
首先,下面的代码是错误的:
get
{
var unityContainer = new UnityContainer();
var httpContextHelper = unityContainer.Resolve<HttpContextHelper>();
return httpContextHelper.GetUser();
}
你正在创建一个新的Unity容器,当然是空,然后你正试图从这个容器中解决一些实例,这将简单地调用HttpContextHelper
类的默认构造函数。天啊,我讨厌Unity,因为当你试图解决一个从未注册到容器中的东西的实例时(这就是你在这里所做的),它没有抛出异常。相反,它会用已知的(已注册的)依赖项静默地调用它的构造函数。
所以这将不会返回你在Bootstrapper中注册的实例,因为在那里你有一个不同的UnityContainer实例,你已经在其中注册了IHttpContextHelper
实例。
public User CurrentUser
{
get
{
var httpContextHelper = DependencyResolver
.Current
.GetService<IHttpContextHelper>();
return httpContextHelper.GetUser();
}
}
现在在你的单元测试中,你可以写一个自定义的依赖解析器:
public class DepepndecyResolverMock : IDependencyResolver
{
private readonly IDictionary<Type, object> kernel;
public DepepndecyResolverMock(IDictionary<Type, object> kernel)
{
this.kernel = kernel;
}
public object GetService(Type serviceType)
{
return this.kernel[serviceType];
}
public IEnumerable<object> GetServices(Type serviceType)
{
throw new NotImplementedException();
}
}
您可以为您的测试配置:
var kernel = new Dictionary<Type, object>
{
{ typeof(IHttpContextHelper), new HttpContextHelperMock() }
};
DependencyResolver.SetResolver(new DepepndecyResolverMock(kernel));
这就是说,这段代码仍然是可怕的错误。它可能允许你对它进行单元测试,但请我坚持,这是错误的设计。不要使用它。它使用服务定位器模式,该模式是一个反模式。正确的方法是反转这个类的控制,这样它就不需要获取它的依赖项,但是它的依赖项需要被注入到它里面。因此,与其把时间浪费在无用的模式上,不如重构代码,让它使用真正的依赖注入。