单元测试



在一个类中,我使用以下代码:

    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实例。

所以重构的第一步是使用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));
这就是说,这段代码仍然是可怕的错误。它可能允许你对它进行单元测试,但请我坚持,这是错误的设计。不要使用它。它使用服务定位器模式,该模式是一个反模式。正确的方法是反转这个类的控制,这样它就不需要获取它的依赖项,但是它的依赖项需要被注入到它里面。因此,与其把时间浪费在无用的模式上,不如重构代码,让它使用真正的依赖注入。

相关内容

  • 没有找到相关文章

最新更新