使用Moq模拟HttpContext.Current.Server.MapPath?

我单位测试我的家庭控制器。 此测试工作正常,直到我添加了一个保存图像的新function。

引起问题的方法如下。

public static void SaveStarCarCAPImage(int capID) { byte[] capBinary = Motorpoint2011Data.RetrieveCapImageData(capID); if (capBinary != null) { MemoryStream ioStream = new MemoryStream(); ioStream = new MemoryStream(capBinary); // save the memory stream as an image // Read in the data but do not close, before using the stream. using (Stream originalBinaryDataStream = ioStream) { var path = HttpContext.Current.Server.MapPath("/StarVehiclesImages"); path = System.IO.Path.Combine(path, capID + ".jpg"); Image image = Image.FromStream(originalBinaryDataStream); Image resize = image.GetThumbnailImage(500, 375, null, new IntPtr()); resize.Save(path, System.Drawing.Imaging.ImageFormat.Jpeg); } } } 

由于调用来自unit testing,HttpContext.Current为null并抛出exception。 在阅读了Moq以及关于将Moq与会话一起使用的一些教程之后,我确信它可以完成。

到目前为止,unit testing代码已经提出,但问题是HTTPContext.Current始终为null,并且仍然抛出exception。

  protected ControllerContext CreateStubControllerContext(Controller controller) { var httpContextStub = new Mock { DefaultValue = DefaultValue.Mock }; return new ControllerContext(httpContextStub.Object, new RouteData(), controller); } [TestMethod] public void Index() { // Arrange HomeController controller = new HomeController(); controller.SetFakeControllerContext(); var context = controller.HttpContext; Mock.Get(context).Setup(s => s.Server.MapPath("/StarVehiclesImages")).Returns("My Path"); // Act ViewResult result = controller.Index() as ViewResult; // Assert HomePageModel model = (HomePageModel)result.Model; Assert.AreEqual("Welcome to ASP.NET MVC!", model.Message); Assert.AreEqual(typeof(List), model.VehicleMakes.GetType()); Assert.IsTrue(model.VehicleMakes.Exists(x => x.Make.Trim().Equals("Ford", StringComparison.OrdinalIgnoreCase))); } 

如果您希望对代码进行unit testing,那么您绝对不应该使用HttpContext.Current 。 它是一个静态方法,如果没有Web上下文就是unit testing并且无法模拟,则它只返回null。 因此,重构代码的一种方法如下:

 public static void SaveStarCarCAPImage(int capID, string path) { byte[] capBinary = Motorpoint2011Data.RetrieveCapImageData(capID, path); if (capBinary != null) { MemoryStream ioStream = new MemoryStream(); ioStream = new MemoryStream(capBinary); // save the memory stream as an image // Read in the data but do not close, before using the stream. using (Stream originalBinaryDataStream = ioStream) { path = System.IO.Path.Combine(path, capID + ".jpg"); Image image = Image.FromStream(originalBinaryDataStream); Image resize = image.GetThumbnailImage(500, 375, null, new IntPtr()); resize.Save(path, System.Drawing.Imaging.ImageFormat.Jpeg); } } } 

您看,现在这种方法不再依赖于任何Web上下文,可以单独测试。 调用者负责传递正确的路径。

我同意Darin的回答,但是如果你真的需要moq Server.MapPath函数,你可以做这样的事情

 //... var serverMock = new Mock(MockBehavior.Loose); serverMock.Setup(i => i.MapPath(It.IsAny())) .Returns((String a) => a.Replace("~/", @"C:\testserverdir\").Replace("/",@"\")); //... 

执行此操作,mock将简单地用〜:/ testserverdir \函数替换〜/

希望能帮助到你!

有时候只是模拟对server.MapPath的调用是很方便的。 这个解决方案适用于我使用moq。 我只模拟应用程序的基本路径。

  _contextMock = new Mock(); _contextMock.Setup(x => x.Server.MapPath("~")).Returns(@"c:\yourPath\App"); _controller = new YourController(); _controller.ControllerContext = new ControllerContext(_contextMock.Object, new RouteData(), _controller); 

在您的控制器中,您现在可以使用Server.MapPath(“〜”)。