【问题标题】:How to unit test code that uses HostingEnvironment.MapPath如何对使用 HostingEnvironment.MapPath 的代码进行单元测试
【发布时间】:2012-02-03 03:49:08
【问题描述】:

我有一些使用HostingEnvironment.MapPath 的代码,我想对其进行单元测试。

如何设置 HostingEnvironment 以便它在我的单元测试 (mstest) 项目中返回路径而不是 null

【问题讨论】:

  • 为什么在 ASP.NET MVC 应用程序中有一个依赖于 HostingEnvironment.MapPath 的代码,您可以在其中访问像 HttpServerUtilityBase 这样的对象,这样您就可以实现这一目标并且可以轻松地模拟和单元测试?也许你可以展示这段代码并解释场景以便我们改进它?
  • @DarinDimitrov:因为我不知道HttpServerUtilityBase。可以举个例子吗?

标签: asp.net asp.net-mvc-3 unit-testing


【解决方案1】:

为什么您会在 ASP.NET MVC 应用程序中拥有一个依赖于 HostingEnvironment.MapPath 的代码,在该应用程序中您可以访问诸如 HttpServerUtilityBase 之类的对象,这些对象允许您实现这一目标,并且可以轻松地进行模拟和单元测试?

让我们举个例子:一个控制器动作,它使用我们要单元测试的抽象 Server 类:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var file = Server.MapPath("~/App_Data/foo.txt");
        return View((object)file);
    }
}

现在,有很多方法可以对这个控制器动作进行单元测试。我个人喜欢使用MVcContrib.TestHelper

但让我们看看如何使用开箱即用的模拟框架来做到这一点。我在这个例子中使用了 Rhino Mocks:

[TestMethod]
public void Index_Action_Should_Calculate_And_Pass_The_Physical_Path_Of_Foo_As_View_Model()
{
    // arrange
    var sut = new HomeController();
    var server = MockRepository.GeneratePartialMock<HttpServerUtilityBase>();
    var context = MockRepository.GeneratePartialMock<HttpContextBase>();
    context.Expect(x => x.Server).Return(server);
    var expected = @"c:\work\App_Data\foo.txt";
    server.Expect(x => x.MapPath("~/App_Data/foo.txt")).Return(expected);
    var requestContext = new RequestContext(context, new RouteData());
    sut.ControllerContext = new ControllerContext(requestContext, sut);

    // act
    var actual = sut.Index();

    // assert
    var viewResult = actual as ViewResult;
    Assert.AreEqual(viewResult.Model, expected);
}

【讨论】:

  • 如果我们测试的是ApiController 而不是MVC 怎么办?
  • 如果我们测试的不是控制器而是实用程序类怎么办?
  • 如果您正在测试不属于您的代码,并且您想根据不存在的测试对其进行反思,该怎么办?
【解决方案2】:

好吧,我今天正在为我无法控制但他们使用的代码编写测试

    private static String GetApplicationPath()
    {
        return HostingEnvironment.ApplicationVirtualPath.TrimEnd('/');
    }

所以这是一个用于设置该值的 C# 反射技巧

var path =  "/aaaa/bb";

HostingEnvironment hostingEnvironment;
if (HostingEnvironment.IsHosted.isFalse())
    new HostingEnvironment();

hostingEnvironment = (HostingEnvironment)typeof(HostingEnvironment).fieldValue("_theHostingEnvironment");

var virtualPath = "System.Web".assembly()
                   .type("VirtualPath").ctor();

virtualPath.field("_virtualPath", path);
//return virtualPath.prop("VirtualPathString");                
//return virtualPath.prop("VirtualPathStringNoTrailingSlash");                 

hostingEnvironment.field("_appVirtualPath", virtualPath);
//hostingEnvironment.field("_appVirtualPath") == virtualPath;

return HostingEnvironment.ApplicationVirtualPath == path;       

//using  System.Web.Hosting

【讨论】:

    【解决方案3】:

    这取决于您使用的模拟或隔离框架。您可能想要研究a)围绕可以模拟的静态属性创建一个包装器类型,或者b)使用可以模拟静态属性的框架 - 例如MolesTypemock Isolator

    【讨论】:

      【解决方案4】:

      当我遇到同样的问题时,我更改了我的代码位。 来自

      strhtmlTemplate = File.ReadAllText(System.Web.Hosting.HostingEnvironment.MapPath(Lgetfilepath.CVal));
      

      收件人

      strhtmlTemplate = File.ReadAllText(HttpContextFactory.Current.Server.MapPath(Lgetfilepath.CVal));
      

      用于单元测试

      public HttpContextBase mockHttpContextBase()
              {
                  var moqContext = new Mock<HttpContextBase>();
                  var moqRequest = new Mock<HttpRequestBase>();
                  var moqServer = new Mock<HttpServerUtilityBase>();
                  var moqPath = new Mock<ConfigurationBase>();
                  moqContext.Setup(x => x.Request).Returns(moqRequest.Object);
                  moqContext.Setup(x => x.Server.MapPath(@"~\Data\xxxxxxx")).Returns(Environment.CurrentDirectory+@"\xxxxxx");                
                  setupApplication(moqContext);
      
                  return moqContext.Object;
              }
      

      现在我们在编写 TestClass 时需要参考上面的方法来模拟。希望对您的测试用例有所帮助。

      MockDataUT mockData = new MockDataUT();
      var mockRequestContext = new HttpRequestContext();
      HttpContextFactory.SetCurrentContext(mockData.mockHttpContextBase());
      

      【讨论】:

        【解决方案5】:

        只需使用此代码..

        在根目录中创建一个新的文件夹名称引用并将您的文件添加到此文件夹中。

        使用这个

        public static XElement GetFile()
        {
            HttpContext.Current = new HttpContext(new HttpRequest("", "http://www.google.com", ""), new HttpResponse(new StringWriter()));
        
            var doc = new XmlDocument();
            var file = HttpContext.Current.Server.MapPath("\\") + "abc.xml";
            doc.Load(file);
            var e = XElement.Load(new XmlNodeReader(doc));
            return e;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多