单元测试unityContainer.Resolve

Rog*_*Far 2 c# asp.net-mvc unit-testing moq unity-container

在我正在使用此代码的类中:

    public User CurrentUser
    {
        get
        {
            var unityContainer = new UnityContainer();
            var httpContextHelper = unityContainer.Resolve<HttpContextHelper>();
            return httpContextHelper.GetUser();
        }
    }
Run Code Online (Sandbox Code Playgroud)

这是在Bootstrapper.cs文件中:

public static class Bootstrapper
{
    public static void Initialise()
    {
        IUnityContainer unityContainer = new UnityContainer();
        unityContainer.RegisterType<IHttpContextHelper, HttpContextHelper>();
        DependencyResolver.SetResolver(new UnityDependencyResolver(unityContainer));
    }
}
Run Code Online (Sandbox Code Playgroud)

我不能在这里使用构造函数注入,因为它是一个基类,重构需要相当多的工作.

但是我如何对此进行单元测试呢?我找不到合适的模拟方法unityContainer.Resolve.

Dar*_*rov 10

首先,以下代码是错误的:

get
{
    var unityContainer = new UnityContainer();
    var httpContextHelper = unityContainer.Resolve<HttpContextHelper>();
    return httpContextHelper.GetUser();
}
Run Code Online (Sandbox Code Playgroud)

您正在创建一个新的Unity容器,当然它是空的,然后您尝试从此容器中解析一些实例,这些实例只是调用HttpContextHelper该类的默认构造函数.Gosh我讨厌Unity,当你试图解决一个从未注册到容器中的事物的实例时(这就是你在这里做的),不会抛出异常.相反,它默默地使用大多数已知(已注册)的依赖项来调用其构造函数.

因此,这不会返回您在Bootstrapper中注册的实例,因为您有一个不同的UnityContainer实例,您已在其中注册了IHttpContextHelper实例.

因此,重构这一步的第一步是使用DependencyResolver:

public User CurrentUser
{
    get
    {
        var httpContextHelper = DependencyResolver
            .Current
            .GetService<IHttpContextHelper>();
        return httpContextHelper.GetUser();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,在单元测试中,您可以编写自定义依赖项解析器:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以为测试配置:

var kernel = new Dictionary<Type, object>
{
    { typeof(IHttpContextHelper), new HttpContextHelperMock() }
};
DependencyResolver.SetResolver(new DepepndecyResolverMock(kernel));
Run Code Online (Sandbox Code Playgroud)

话虽这么说,这段代码仍然是非常错误的.它可能允许你对它进行单元测试,但我请坚持,这是错误的设计.不要使用它.这使用了服务定位器模式,这是一种反模式.

执行此操作的正确方法是反转此类的控件,以便它不需要获取其依赖项,但需要将其依赖项注入其中.因此,不要在无用的模式中浪费你的时间,而是重构你的代码,以便它使用真正的依赖注入.

  • 感谢建设性的批评,我很感激.但对这个问题有什么建议吗?我有这个基类,它由很多MVC4控制器继承.问题是这不是唯一必须解决的类. (2认同)