C# 单元测试MVC控制器-需要应用程序的路径

C# 单元测试MVC控制器-需要应用程序的路径,c#,asp.net-mvc,unit-testing,C#,Asp.net Mvc,Unit Testing,我继承了一个旧的ASP.net MVC应用程序,我试图反写单元测试,但遇到了一个错误。下面是我的单元测试: public void DashboardController_Index_ReturnsIndex() { var dashboardController = _mocker.Resolve<DashboardController>(); var controllerContextMock = new Mock<Contro

我继承了一个旧的ASP.net MVC应用程序,我试图反写单元测试,但遇到了一个错误。下面是我的单元测试:

public void DashboardController_Index_ReturnsIndex()
     {
         var dashboardController = _mocker.Resolve<DashboardController>();
         var controllerContextMock = new Mock<ControllerContext>();
         var userMock = new Mock<IUserContext>();

         userMock
             .SetupGet(u => u.Identity.IsAuthenticated)
             .Returns(true);
         userMock
             .Setup(u => u.Type)
             .Returns(EUserType.Normal);
         controllerContextMock
             .SetupGet(c => c.HttpContext.User)
             .Returns(userMock.Object);
         controllerContextMock
             .SetupGet(p => p.HttpContext.Request.Url)
             .Returns(new Uri("http://localhost/Dashboard/Index"));

         dashboardController.ControllerContext = controllerContextMock.Object;

         var result = dashboardController.Index() as ViewResult;

         Assert.Equal("Index", result.ViewName);
     }
此方法的第三行出现异常,代码尝试将字符串拆分为字段。具体来说,这里有一个例外:

System.Web.HttpException(0x80004005):无法将应用程序相对虚拟路径“~/”设置为绝对路径,因为应用程序的路径未知


我已经看到它描述了如何在这个调用中注入一个假字符串,但是由于控制器本身并没有试图解析字符串,而是将它传递给另一个类中的一个helper方法,因此DI似乎不起作用。知道我如何在单元测试时伪造应用程序路径吗?在生产中,这段代码工作得很好。我想我可以重构控制器,将这个helper类用作依赖项,而不只是调用静态方法,但我希望找到一个不需要对生产代码进行代码更改的解决方案。

不幸的是,正确的方法是,需要重构生产代码,以允许将helper方法作为依赖项注入。毕竟,创建单元测试以允许自信地重构代码不是一个优点吗?在这种情况下,生产代码不太容易进行回装单元测试(在尝试这样做时经常如此)


最好的方法是提升一个抽象级别,创建“行为测试”(如在行为驱动开发中),在更高级别上彻底检查控制器的行为,重构它以允许进行单元测试,如果行为没有改变,可以自信地进行重新拟合单元测试。

有趣的问题,希望查看建议的路径/答案。
private static string GetResourceString(HttpContextBase httpContext, string sxExpression, string sxVirtualPath)
        {
            var context = new ExpressionBuilderContext(sxVirtualPath);
            var builder = new ResourceExpressionBuilder();
            var fields = (ResourceExpressionFields)builder.ParseExpression(sxExpression, 
                typeof(string), context);

            if (string.IsNullOrEmpty(fields.ClassKey) == false)
                return (string)httpContext.GetGlobalResourceObject(fields.ClassKey, fields.ResourceKey, 
                    Thread.CurrentThread.CurrentCulture);
            return (string)httpContext.GetLocalResourceObject(sxVirtualPath, fields.ResourceKey, 
                Thread.CurrentThread.CurrentCulture);
        }