2

在一个类中,我正在使用此代码:

    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

4

1 回答 1

11

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

get
{
    var unityContainer = new UnityContainer();
    var httpContextHelper = unityContainer.Resolve<HttpContextHelper>();
    return httpContextHelper.GetUser();
}

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

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

所以重构的第一步是使用 DependencyResolver:

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));

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

做到这一点的正确方法是反转这个类的控制,这样它就不需要获取它的依赖项,但它的依赖项需要注入它。因此,与其将时间浪费在无用的模式上,不如重构您的代码,使其使用真正的依赖注入。

于 2012-12-23T16:47:19.993 回答